0001 function outdata=specscope(indata)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 if not(exist('analoginput'));
0021 fprintf('You need to install the DAQ toolbox first\n');
0022 return
0023 end
0024 if not(exist('mtspecgramc'));
0025 fprintf('You need to install the Chronux toolbox first from http://chronux.org/\n');
0026 return
0027 end
0028
0029 global acq;
0030
0031
0032 acq.moving_window = [0.02 0.02];
0033 acq.params.Fs = 44100;
0034 acq.params.raw_tapers = [2 3];
0035 acq.params.tapers=dpsschk(acq.params.raw_tapers,round(acq.params.Fs*acq.moving_window(1)),acq.params.Fs);
0036 acq.params.pad= 0;
0037 acq.params.fpass = [50 8000];
0038 acq.pause = 0;
0039 acq.skips = 0;
0040 acq.stop = 0;
0041 acq.restart = 0;
0042 acq.plot_frequency = 20;
0043 acq.samples_acquired = 0;
0044 acq.spectra = [];
0045 acq.times = [];
0046 defaults
0047
0048 audio_instr;
0049
0050 fig=create_ui;
0051
0052 if nargout
0053
0054 fprintf('Pre-allocating memory for data save - please be patient.\n');
0055 outdata=zeros( (acq.params.Fs * 60 * 10), 1 );
0056 end
0057
0058 if nargin == 1;
0059 acq.indata = indata;
0060 acq.live = 0;
0061 else
0062
0063 input=1;
0064 if input==1;
0065 acq.ai = analoginput('winsound');
0066 addchannel( acq.ai, 1 );
0067 else
0068 acq.ai = analoginput('nidaq', 1);
0069 addchannel(acq.ai, 0);
0070 set(acq.ai,'InputType','SingleEnded')
0071 set(acq.ai,'TransferMode','Interrupts')
0072 set(acq.ai,'TriggerType','Manual');
0073 end
0074 set( acq.ai, 'SampleRate', acq.params.Fs )
0075 acq.params.Fs = get( acq.ai, 'SampleRate' );
0076 acq.samples_per_frame = acq.params.Fs / acq.plot_frequency;
0077 set( acq.ai, 'SamplesPerTrigger', inf )
0078 start(acq.ai)
0079 acq.live = 1;
0080
0081 if input==2;
0082 trigger(acq.ai);
0083 end
0084 end
0085
0086 acq.t0=clock;
0087 acq.tn=clock;
0088
0089
0090 while 1;
0091
0092
0093 if acq.stop;
0094 break;
0095 end
0096
0097
0098 calctime = acq.samples_acquired / acq.params.Fs;
0099 acq.samples_acquired = acq.samples_acquired + acq.samples_per_frame;
0100 acq.t1 = clock;
0101 elapsed = etime(acq.t1,acq.t0);
0102
0103
0104 if ( acq.live )
0105 data = getdata( acq.ai, acq.samples_per_frame );
0106 else
0107 while elapsed < acq.samples_acquired / acq.params.Fs
0108 pause( acq.samples_acquired / (acq.params.Fs) - elapsed );
0109 acq.t1=clock;
0110 elapsed = etime(acq.t1,acq.t0);
0111 end
0112 if acq.samples_acquired + 2 * acq.samples_per_frame >= length( acq.indata )
0113 acq.stop=1;
0114 end
0115 data = acq.indata(floor(acq.samples_acquired+1):floor(acq.samples_per_frame+acq.samples_acquired));
0116 end
0117
0118 if nargout
0119 outdata(floor(acq.samples_acquired+1):floor(acq.samples_acquired+length(data))) = data(:);
0120 end
0121
0122 if acq.restart;
0123 acq.restart = 0;
0124 acq.spectra = [];
0125 acq.times = [];
0126 end
0127
0128
0129 if acq.deriv
0130 [s, t, f] = mtspecgramc(diff(data), acq.moving_window, acq.params );
0131 else
0132 [s, t, f] = mtspecgramc(data, acq.moving_window, acq.params );
0133 end
0134
0135
0136 acq.times = [acq.times t+calctime];
0137 if acq.log
0138 acq.spectra = [acq.spectra log(s')];
0139 else
0140 acq.spectra = [acq.spectra s'];
0141 end
0142
0143
0144 while acq.times(1,end) - acq.times(1,1) > acq.display_size;
0145
0146
0147 y = length(t);
0148 acq.times(:,1:y) = [];
0149 acq.spectra(:,1:y) = [];
0150
0151 end
0152
0153
0154 show_plot=1;
0155 if nargin==0
0156 if get(acq.ai, 'SamplesAvailable' ) > 10 * acq.samples_per_frame && acq.pause==0
0157 show_plot=0;
0158 end
0159 else
0160 if elapsed > calctime + 0.5
0161 show_plot=0;
0162 end
0163 end
0164
0165 if acq.pause
0166 show_plot=0;
0167 end
0168 if show_plot
0169
0170
0171 if acq.normalize>=1;
0172 if acq.normalize==1
0173 acq.tn=clock;
0174 acq.normalize=2;
0175 end
0176 if etime(clock,acq.tn)>1.25*acq.display_size
0177 acq.normalize=0;
0178 end
0179 mins = min(min(acq.spectra));
0180 maxs = max(max(acq.spectra));
0181 end
0182
0183
0184 scaled_spectra = acq.offset + acq.scale * ( acq.spectra - mins ) / ( maxs - mins );
0185
0186
0187 image( acq.times, f, scaled_spectra ); axis xy;
0188 drawnow;
0189
0190 else
0191
0192 acq.skips = acq.skips + 1;
0193 end
0194
0195 end
0196
0197 acq.t1=clock;
0198 elapsed = etime(acq.t1,acq.t0);
0199 fprintf( 'Elapsed time %f seconds\n', elapsed );
0200
0201
0202 if acq.skips > 5;
0203 fprintf( '\nWARNING:\nThis program skipped plotting %d times to keep pace.\n', acq.skips )
0204 fprintf( 'Run again without keyboard interaction or changing the figure size.\n' )
0205 fprintf( 'If this message reappears you should reduce the plot frequency parameter.\n\n' );
0206 end
0207
0208
0209 if acq.live
0210 stop(acq.ai);delete( acq.ai );clear acq.ai;
0211 end
0212
0213
0214 delete(fig);
0215 delete(gcf);
0216
0217 if nargout
0218
0219 fprintf('Saving output data\n');
0220 outdata=outdata(1:floor(acq.samples_acquired));
0221 end
0222
0223 return;
0224
0225
0226 function keypress(varargin)
0227
0228 global acq;
0229 keypressed=get(gcf,'CurrentCharacter');
0230
0231
0232 if keypressed;
0233
0234
0235 increment=1;
0236 if strcmp( keypressed, 'l');
0237 acq.offset = acq.offset - increment;
0238 elseif strcmp( keypressed, 'o');
0239 acq.offset = acq.offset + increment;
0240
0241
0242 elseif strcmp( keypressed, 'x');
0243 acq.scale = acq.scale - increment;
0244 elseif strcmp( keypressed, 's');
0245 acq.scale = acq.scale + increment;
0246
0247
0248 elseif strcmp( keypressed, 'd');
0249 defaults
0250
0251
0252 elseif strcmp( keypressed, 'n');
0253 request_normalize
0254
0255
0256 elseif strcmp( keypressed, 'q');
0257 request_quit
0258
0259
0260 elseif strcmp( keypressed, 'p');
0261 request_pause
0262
0263
0264 elseif strcmp( keypressed, 'h');
0265 audio_instr
0266
0267
0268 elseif strcmp( keypressed, '0' );
0269 colormap( 'jet' );
0270 elseif strcmp( keypressed, '1' );
0271 colormap( 'bone' );
0272 elseif strcmp( keypressed, '2' );
0273 colormap( 'colorcube' );
0274 elseif strcmp( keypressed, '3' );
0275 colormap( 'cool' );
0276 elseif strcmp( keypressed, '4' );
0277 colormap( 'copper' );
0278 elseif strcmp( keypressed, '5' );
0279 colormap( 'gray' );
0280 elseif strcmp( keypressed, '6' );
0281 colormap( 'hot' );
0282 elseif strcmp( keypressed, '7' );
0283 colormap( 'hsv' );
0284 elseif strcmp( keypressed, '8' );
0285 colormap( 'autumn' );
0286 elseif strcmp( keypressed, '9' );
0287 colormap( 'pink' );
0288 elseif strcmp( keypressed, 'a' );
0289 colormap( 'spring' );
0290 elseif strcmp( keypressed, 'b' );
0291 colormap( 'summer' );
0292 elseif strcmp( keypressed, 'c' );
0293 colormap( 'winter' );
0294 end
0295
0296 update_display
0297
0298 end
0299 return
0300
0301
0302 function defaults()
0303 global acq;
0304 acq.scale = 64;
0305 acq.offset = 0;
0306 acq.deriv=1;
0307 acq.log=1;
0308 acq.deriv2=0;
0309 acq.normalize = 2;
0310 acq.display_size = 3;
0311
0312 return
0313
0314 function update_display()
0315 global acq;
0316 set(acq.offsetui,'String',sprintf( '%d', acq.offset ));
0317 set(acq.scaleui,'String',sprintf( '%d', acq.scale ));
0318 set(acq.log_ui,'Value',acq.log);
0319 set(acq.derivative_ui,'Value',acq.deriv);
0320
0321 return
0322
0323 function update_defaults(varargin)
0324 defaults
0325 colormap('jet');
0326 update_display
0327 return
0328
0329 function audio_instr()
0330
0331
0332 fprintf('INSTRUCTIONS:\n');
0333 fprintf('Click on figure window first to activate controls.\n')
0334 fprintf('Adjust tapers, windows, scales, offsets and axes using the gui\n');
0335 fprintf('The deriv checkbox toggles derivative of the data\n');
0336 fprintf('The log checkbox toggles a log of the spectrum\n');
0337
0338 fprintf('Press d or use defaults button to reset most parameters to defaults.\n')
0339 fprintf('Press n or use normalize button to normalize spectra based upon values in current display.\n')
0340 fprintf('Press 0-9,a-c to choose a colormap (default 0).\n')
0341 fprintf('Press p to pause and unpause display.\n')
0342 fprintf('Press o and l to adjust offset, or use offset textbox on gui.\n');
0343 fprintf('Press s and x to adjust scale, or use scale textbox on gui.\n');
0344 fprintf('Press h for this message.\n')
0345 fprintf('Press q to quit, or use quit button on gui.\n\n')
0346
0347 return
0348
0349 function request_quit(varargin)
0350 global acq;
0351 acq.stop=1;
0352 return
0353
0354 function request_pause(varargin)
0355 global acq;
0356 acq.pause = not( acq.pause );
0357 return
0358
0359 function request_normalize(varargin)
0360 global acq;
0361 acq.normalize = 2;
0362 return
0363
0364 function update_tapers(varargin)
0365 global acq;
0366 acq.params.raw_tapers = sscanf(get( gco, 'string' ),'%f %d')';
0367 acq.params.tapers=dpsschk(acq.params.raw_tapers,round(acq.params.Fs*acq.moving_window(1)),acq.params.Fs);
0368 return
0369
0370 function update_window(varargin)
0371 global acq;
0372 acq.moving_window = sscanf(get( gco, 'string' ),'%f %f');
0373 acq.restart = 1;
0374 return
0375
0376 function update_offset(varargin)
0377 global acq;
0378 acq.offset = sscanf(get( gco, 'string' ),'%f');
0379 return
0380
0381 function update_scale(varargin)
0382 global acq;
0383 acq.scale = sscanf(get( gco, 'string' ),'%f');
0384 return
0385
0386 function update_display_size(varargin)
0387 global acq;
0388 acq.display_size = sscanf(get( gco, 'string' ),'%f');
0389 return
0390
0391 function update_fpass(varargin)
0392 global acq;
0393 acq.params.fpass = sscanf(get( gco, 'string' ),'%f %f');
0394 acq.restart = 1;
0395 return
0396
0397 function update_deriv(varargin)
0398 global acq;
0399 acq.deriv=get( gco, 'Value' );
0400 acq.normalize=1;
0401 return
0402
0403 function update_log(varargin)
0404 global acq;
0405 acq.log=get( gco, 'Value' );
0406 acq.normalize=1;
0407 return
0408
0409 function update_deriv2(varargin)
0410 global acq;
0411 acq.deriv2=get( gco, 'Value' );
0412 acq.normalize=1;
0413 acq.restart=1;
0414 return
0415
0416 function pos = centerfig(width,height)
0417
0418 screen_s = get(0,'ScreenSize');
0419 pos = [screen_s(3)/2 - width/2, screen_s(4)/2 - height/2, width, height];
0420 return
0421
0422
0423 function fig=create_ui()
0424 global acq;
0425
0426 bgcolor = [.7 .7 .7];
0427
0428
0429 fig = figure('Position',centerfig(800,600),...
0430 'NumberTitle','off',...
0431 'Name','Real-time spectrogram',...
0432 'doublebuffer','on',...
0433 'HandleVisibility','on',...
0434 'Renderer', 'openGL', ...
0435 'KeyPressFcn', @keypress, ...
0436 'Color',bgcolor);
0437
0438
0439 uicontrol('Style','pushbutton',...
0440 'Position',[5 5 45 20],...
0441 'String','Quit',...
0442 'Interruptible','off',...
0443 'BusyAction','cancel',...
0444 'Callback',@request_quit);
0445
0446
0447 uicontrol('Style','pushbutton',...
0448 'Position',[55 5 45 20],...
0449 'String','Pause',...
0450 'Interruptible','off',...
0451 'BusyAction','cancel',...
0452 'Callback',@request_pause);
0453
0454
0455 uicontrol('Style','pushbutton',...
0456 'Position',[105 5 50 20],...
0457 'String','Defaults',...
0458 'Interruptible','off',...
0459 'BusyAction','cancel',...
0460 'Callback',@update_defaults);
0461
0462
0463 uicontrol('Style','pushbutton',...
0464 'Position',[160 5 60 20],...
0465 'String','Normalize',...
0466 'Interruptible','off',...
0467 'BusyAction','cancel',...
0468 'Callback',@request_normalize );
0469
0470
0471 uicontrol(gcf,'Style','text',...
0472 'String', 'tapers',...
0473 'Position',[225 20 45 20],...
0474 'BackgroundColor',bgcolor);
0475 uicontrol(gcf,'Style','text',...
0476 'String', 'moving win',...
0477 'Position',[300 20 70 20],...
0478 'BackgroundColor',bgcolor);
0479 uicontrol(gcf,'Style','text',...
0480 'String', 'offset',...
0481 'Position',[375 20 30 20],...
0482 'BackgroundColor',bgcolor);
0483 uicontrol(gcf,'Style','text',...
0484 'String', 'scale',...
0485 'Position',[410 20 30 20],...
0486 'BackgroundColor',bgcolor);
0487 uicontrol(gcf,'Style','text',...
0488 'String', 't axis',...
0489 'Position',[445 20 30 20],...
0490 'BackgroundColor',bgcolor);
0491 uicontrol(gcf,'Style','text',...
0492 'String', 'f axis',...
0493 'Position',[480 20 40 20],...
0494 'BackgroundColor',bgcolor);
0495 uicontrol(gcf,'Style','text',...
0496 'String', 'deriv',...
0497 'Position',[555 20 35 20],...
0498 'BackgroundColor',bgcolor);
0499 uicontrol(gcf,'Style','text',...
0500 'String', 'log',...
0501 'Position',[585 20 35 20],...
0502 'BackgroundColor',bgcolor);
0503
0504
0505
0506
0507
0508
0509 uicontrol(gcf,'Style','edit',...
0510 'String', sprintf( '%.1f %.0f', acq.params.raw_tapers(1), acq.params.raw_tapers(2) ),...
0511 'Position',[225 5 70 20],...
0512 'CallBack', @update_tapers);
0513
0514
0515 uicontrol(gcf,'Style','edit',...
0516 'String', sprintf( '%.2f %.2f', acq.moving_window(1), acq.moving_window(2) ),...
0517 'Position',[300 5 70 20],...
0518 'CallBack', @update_window);
0519
0520
0521 acq.offsetui = uicontrol(gcf,'Style','edit',...
0522 'String', sprintf( '%d', acq.offset ),...
0523 'Position',[375 5 30 20],...
0524 'CallBack', @update_offset);
0525
0526
0527 acq.scaleui = uicontrol(gcf,'Style','edit',...
0528 'String', sprintf( '%d', acq.scale ),...
0529 'Position',[410 5 30 20],...
0530 'CallBack', @update_scale);
0531
0532
0533 acq.display_size_ui = uicontrol(gcf,'Style','edit',...
0534 'String', sprintf( '%.1f', acq.display_size ),...
0535 'Position',[445 5 30 20],...
0536 'CallBack', @update_display_size);
0537
0538
0539 acq.frequency_ui = uicontrol(gcf,'Style','edit',...
0540 'String', sprintf( '%.1f %.1f', acq.params.fpass(1), acq.params.fpass(2) ),...
0541 'Position',[480 5 80 20],...
0542 'CallBack', @update_fpass);
0543
0544
0545 acq.derivative_ui = uicontrol(gcf,'Style','checkbox',...
0546 'Value',acq.deriv,...
0547 'Position',[565 5 20 20],...
0548 'CallBack', @update_deriv);
0549
0550
0551 acq.log_ui = uicontrol(gcf,'Style','checkbox',...
0552 'Value',acq.log,...
0553 'Position',[590 5 20 20],...
0554 'CallBack', @update_log);
0555
0556
0557
0558
0559
0560
0561
0562 return