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
35 gi.require_version('Gst', '1.0')
36 from gi.repository import GObject, Gst
39 from gstlal import simplehandler
40 from gstlal import pipeparts
41 from gstlal import datasource
44 from ligo import segments
48 # =============================================================================
52 # =============================================================================
56 def parse_command_line():
57 parser = OptionParser(
58 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"
60 # generic "source" options
61 datasource.append_options(parser)
62 parser.add_option("--sample-rate", metavar = "Hz", type = "float", default = 8192.0, help = "Downsample the data to this sample rate. Default = 8192 Hz.")
63 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).")
64 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).")
65 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.")
66 parser.add_option("--median-samples", metavar = "samples", type = "int", default = 5, help = "Set the number of samples in the median history (optional). Default = 5.")
67 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.")
68 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.")
69 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.")
70 parser.add_option("-v", "--verbose", action = "store_true", help = "Be verbose (optional).")
72 options, filenames = parser.parse_args()
74 if options.f_max <= options.f_min:
75 raise ValueError, "--f-max must be >= --f-min"
77 return options, filenames
81 # =============================================================================
85 # =============================================================================
94 options, filenames = parse_command_line()
98 # parse the generic "source" options, check for inconsistencies is done inside
99 # the class init method
103 gw_data_source_info = datasource.GWDataSourceInfo(options)
104 if len(gw_data_source_info.channel_dict) != 1:
105 raise ValueError("can only specify one channel, one instrument")
106 instrument, = gw_data_source_info.channel_dict.keys()
114 def build_pipeline(pipeline, head, sample_rate, psd_fft_length, psd_zero_pad_length, average_length, median_samples, (f_min, f_max), verbose = False):
115 head = pipeparts.mkresample(pipeline, head, quality = 9)
116 head = pipeparts.mkcapsfilter(pipeline, head, "audio/x-raw, rate=%d" % sample_rate)
117 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)
118 pipeparts.mkfakesink(pipeline, head)
119 head = pipeparts.mkqueue(pipeline, head.get_static_pad("mean-psd"), max_size_buffers = 4)
121 head = pipeparts.mkspectrumplot(pipeline, head, f_min = f_min, f_max = f_max)
122 head = pipeparts.mkcapsfilter(pipeline, head, "video/x-raw-rgb, width=768, height=320")
127 # construct and run pipeline
131 mainloop = GObject.MainLoop()
132 pipeline = Gst.Pipeline(name="spectrum-movie")
133 handler = simplehandler.Handler(mainloop, pipeline)
136 head, _, _ = datasource.mkbasicsrc(pipeline, gw_data_source_info, instrument, verbose = options.verbose)
137 head = build_pipeline(
141 options.psd_fft_length,
142 options.psd_zero_pad_length,
143 options.average_length,
144 options.median_samples,
145 (options.f_min, options.f_max),
146 verbose = options.verbose
148 if options.output is not None:
149 pipeparts.mkogmvideosink(pipeline, head, options.output, verbose = options.verbose)
151 pipeparts.mkvideosink(pipeline, pipeparts.mkcolorspace(pipeline, head))
159 if pipeline.set_state(Gst.State.PLAYING) == Gst.StateChangeReturn.FAILURE:
160 raise RuntimeError("pipeline failed to enter PLAYING state")