diff saitools/saigraph.c @ 0:5242703e91d3 tip

Initial checkin for AIM92 aimR8.2 (last updated May 1997).
author tomwalters
date Fri, 20 May 2011 15:19:45 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/saitools/saigraph.c	Fri May 20 15:19:45 2011 +0100
@@ -0,0 +1,465 @@
+/*
+    Copyright (c) Applied Psychology Unit, Medical Research Council. 1993
+    ===========================================================================
+
+    Permission to use, copy, modify, and distribute this software without fee 
+    is hereby granted for research purposes, provided that this copyright 
+    notice appears in all copies and in all supporting documentation, and that 
+    the software is not redistributed for any fee (except for a nominal 
+    shipping charge). Anyone wanting to incorporate all or part of this 
+    software in a commercial product must obtain a license from the Medical 
+    Research Council.
+
+    The MRC makes no representations about the suitability of this 
+    software for any purpose.  It is provided "as is" without express or 
+    implied warranty.
+ 
+    THE MRC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 
+    ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 
+    THE A.P.U. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES 
+    OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 
+    WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 
+    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
+    SOFTWARE.
+*/
+
+/*------------------------------------------------------------------------*/
+
+/*  saigraph.c
+*  --------------
+*  
+* Works out the (first-order) temporal intervals between peaks in a .sai file,
+* and saves them in a SINGLE-FRAME .sai
+* In essence, a histogram.
+*
+* Uses ALL peaks: if you just want the locallly maxima peaks, then use 
+* trbigpeak first.
+*
+* Output is another .sai file: but only a single frame. The header is
+* modified accordingly.
+* 
+*
+*
+* M. Akeroyd.   May 1993.   Version 2.0
+*
+*               Autumn 1993: added grayscaleflag
+*               Winter 1994: allowed weighting, and other general revisions.
+*/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "tip.h"
+
+
+/* Function declarations */
+/*------------------------------------------------------------*/
+
+void parsecommandline (int argc, char *argv[], char inputfn[], char outputfn[]);
+
+int readheader(FILE *inputfp);
+void checkheader();
+void writeheader(FILE *outputfp);
+
+void changeheader(int no_frames, int new_pwidth, int new_nwidth, int framewidth_samples_output);
+
+int findpeaksreverse (); 
+void find_intervals(int total_peaks, int channel, int max_interval);
+
+void writedata_output (FILE *outputfp, int samples_to_write);
+void writedata_output_fg (FILE *figurefp, FILE *groundfp, int samples_to_write);
+FILE *open_file (char filefn[], FILE *dir_default, int streamtype);
+
+void copytooutput_fg_single (int total_peaks, int frame, int channel, int trigger_peak);
+
+void write_matrix_hori_time(int framewidth, FILE *outputfigurefp);
+void write_matrix_hori_freq(int framewidth, FILE *outputfigurefp);
+
+
+
+
+/* Data arrays: global */
+/*-----------------------------------------------------------------*/
+
+
+short inputdata[MAX_DATA];        /* input .sai: a single channel of a frame */
+short outputdata[MAX_DATA];       /* output .sai: a single channel */
+short outputfiguredata[MAX_DATA]; /* output figure.sai: a single channel */
+short outputgrounddata[MAX_DATA]; /* output ground.sai: a single channel */
+short clip[MAX_CHANNELS];
+
+short interval[MAX_CHANNELS][MAX_DATA];      /* histogram */ 
+short summation[MAX_CHANNELS];
+
+
+
+/* other variables */
+/*----------------------------------------------------------------*/
+
+struct Peak peak[MAX_PEAKS];                    /* used in findpeaksreverse():
+						 * single channel */
+struct NextEvent nextevent[MAX_NEXTEVENTS];     /* used in findpeaksreverse():
+						 * single channel */
+
+
+
+/* variables read from header */
+/*---------------------------------------------------------------*/
+
+char header[MAX_LINES_HEADER][MAX_LINE_LENGTH];
+int header_lines;
+
+int no_frames;
+int frameheight;             /* number of channels */
+int framewidth_samples;      /* pwidth + nwidth * samplerate */
+int frameshift_samples;      /* frstep_aid * samplerate */
+int pwidth;                  /* in msecs */
+int nwidth;                  /* in msecs: NEGATIVE */
+int width_win;               /* pixels */
+int height_win;              /* pixels */
+long samplerate;             /* samples per sec */
+int mincf;                   /* Hz */
+int maxcf;                   /* Hz */
+
+
+
+
+/* misc */
+/*-----------------------------------------------------------*/
+
+char progname[MAX_STRING_LENGTH];
+char outputfigurefn[MAX_STRING_LENGTH];
+
+
+int verboseflag = OFF;               /* -v */
+int removeflag = OFF;                /* -r */
+double removevalue = 0.1;            
+int widthflag = OFF;                 /* -width : if OFF, copy pwdith/nwidth 
+				      *      off Input .sai */
+int total_width;                     /* -width : total width of new .sai */
+int asciiflag = OFF;                 /* -a */
+int asciireverseflag = OFF;          /* -ar */
+int summationflag = OFF;             /* -s */
+int greyscaleflag = OFF;             /* -g */
+int weightflag = OFF;             /* -weight */
+int oppositearchflag = OFF;          /* -oparch: if ON, then the header-reading
+				      * code will load one (1) extra byte. This
+				      * is so that Sun .sai/.nap can be read
+				      * on a DEC, and equally the reverse.
+				      * It is NOT required if reading Sun on
+				      * Sun, or DEC on DEC. */
+
+
+
+/*...............           Main           ................................*/
+/*.........................................................................*/
+/*.........................................................................*/
+
+
+
+void main (int argc, char *argv[])
+{
+  int sample;
+  int n;
+
+  int frame, channel;
+  int trigger_peak = 0;
+  int no_peak = 0, total_peaks =0, total_peaks_2;
+  int framewidth_samples_input,
+      framewidth_samples_output;
+  int new_pwidth, 
+      new_nwidth;
+  int header_bytes = 0;
+ 
+  char inputfn[MAX_STRING_LENGTH], 
+       outputbasefn[MAX_STRING_LENGTH];
+
+  FILE *inputfp, *outputfigurefp;
+
+  int clipflag = OFF;
+
+/*-----------------------------------------*/
+
+  strcpy(progname, argv[0]);
+  strcpy(inputfn, "");
+  strcpy(outputbasefn, "");
+  strcpy(outputfigurefn, "");
+
+  /* parse command line */
+  parsecommandline(argc, argv, inputfn, outputbasefn);
+
+  if (strcmp(outputbasefn, "") == 0) 
+    strcpy(outputfigurefn, "");
+  else 
+    strcpy(outputfigurefn, outputbasefn);
+
+
+  /* open files */
+  /* default directions are:
+   * input = stdin 
+   * figure = stdout
+   */
+
+  inputfp = open_file(inputfn, stdin, READ);
+  outputfigurefp = open_file(outputfigurefn, stdout, WRITE);
+
+  /* read Header */
+  header_bytes = readheader(inputfp);
+  checkheader();
+
+
+  /* reset the variables */
+  framewidth_samples_input = framewidth_samples;
+  if (widthflag == OFF) {
+    new_pwidth = + pwidth;
+    new_nwidth = -nwidth;
+    framewidth_samples_output = framewidth_samples_input;}
+  else {
+    new_pwidth = + NEW_PWIDTH;
+    new_nwidth = (new_pwidth + total_width);
+    framewidth_samples_output = (int) ((int) (abs(new_pwidth) + abs (new_nwidth)) * samplerate ) / 1000;}
+
+  if (framewidth_samples_output >= MAX_DATA) {
+    fprintf(stderr, "%s: new frame is  too wide at %i: only allowed %i samples\n", progname, framewidth_samples_output, MAX_DATA);
+    exit(-1); }
+
+
+  /* change header */
+  changeheader(1, new_pwidth, new_nwidth, framewidth_samples_output);
+
+  /* write header */
+  if (asciiflag == OFF) 
+    writeheader(outputfigurefp);
+  else {
+    /* begining of ascii header. The rest depends on the matrix format ... */
+    fprintf(outputfigurefp, "# saigraph output.  %s\n", inputfn);
+    fprintf(outputfigurefp, "# \n");
+    fprintf(outputfigurefp, "# samplerate=%i  pwidth=%d  nwidth=%d  frames=%i ", samplerate, pwidth, nwidth, no_frames);
+    fprintf(outputfigurefp, " mincf=%i  maxcf=%i  channels=%i \n", mincf, maxcf,  frameheight);
+    fprintf(outputfigurefp, "# \n");
+  }
+
+/*------------------------------------------*/
+
+  /* Main loop */
+
+  if  (verboseflag == ON) { 
+    fprintf(stderr, " frames "); 
+    fflush(stderr);}
+
+  
+  /* clear arrays */
+  
+  for (channel=0; channel<MAX_CHANNELS; channel++) {
+    for(sample=0; sample<MAX_DATA; sample++)
+      interval[channel][sample] = 0;
+    clip[channel]=OFF;
+  }
+
+
+  /* reset this, so everything still works */
+  framewidth_samples = framewidth_samples_input;
+
+
+  for (frame=1; frame<=no_frames; frame++) {
+
+    if  (verboseflag == ON) { 
+      fprintf(stderr, " %i ", frame); 
+      fflush(stderr);}
+
+    /*--------------------------------------------*/
+
+    /* load the whole frame's worth of data first */
+
+    for (channel=1; channel <=frameheight; channel ++) {
+
+      /* clear arrays */
+      for(sample=0; sample<framewidth_samples; sample++) 
+	inputdata[sample] = outputdata[sample] = 0;
+      for(n=0; n < MAX_PEAKS; n++){
+	peak[n].tent = UNSET;
+	peak[n].sample=0;}
+
+      /* Nextevents are unnecessary */
+
+      /* load a single channel's worth of data */
+      fread (inputdata, 2, (size_t) framewidth_samples, inputfp);
+
+      /* This next is a simple input check: if any numbers < 0, then say so */
+      for(sample=0; sample<framewidth_samples; sample++)
+	if (inputdata[sample] < 0 )  {
+	  fprintf(stderr, "%s: something's gone wrong: the data is negative.\n", progname);
+	  exit(-1); }
+
+      /* find peaks. WARNING: in reverse */
+      total_peaks = findpeaksreverse();
+
+      /* bin any small peaks ... */
+      if ((removeflag == ON) && (total_peaks !=0 ) ) {
+        total_peaks_2 = removepeaks(total_peaks);
+        for(n=0; n < MAX_PEAKS; n++) {
+          peak[n].tent = UNSET;
+          peak[n].sample = 0;}
+        total_peaks = findpeaksreverse();}
+
+      /* get intervals */
+      find_intervals(total_peaks, channel, framewidth_samples_output);
+
+    } /* channel */
+
+  } /* frame */
+
+
+/*------------------------------------------*/
+/*------------------------------------------*/
+
+
+  fflush(stdout);
+
+
+  /* If required, sum the values */
+  if (summationflag==ON) {
+
+    for (channel = 1; channel <= frameheight; channel ++)
+	summation[channel] = 0;
+
+    for (channel = 1; channel <= frameheight; channel ++) {
+      clipflag = OFF;
+      for (sample = 0; sample < framewidth_samples_output; sample++)
+	summation[channel] += interval[channel][sample];
+
+      /* clip check */
+      if ((summation[channel] > 32765) || 
+	  (summation[channel] < 0)){
+	    if (clipflag == OFF) {
+	      fprintf(stderr, " \nclipping: channel %i, summations.\n ", channel);
+	      clipflag = ON;}
+	    summation[channel] = 32765;
+	  }
+    }
+  }
+
+/*-------------------------------------------*/
+
+  /* write output */
+
+  if (asciiflag == OFF) {
+    for (channel = 1; channel <= frameheight; channel ++){
+      for (sample = 0; sample < framewidth_samples_output; sample++)
+	outputfiguredata[sample] = interval[channel][sample];
+      writedata_output(outputfigurefp, framewidth_samples_output);
+    }
+  }  
+  else {
+    if (asciireverseflag == OFF) 
+      write_matrix_hori_freq(framewidth_samples_output, outputfigurefp);
+    else
+      write_matrix_hori_time(framewidth_samples_output, outputfigurefp);
+  }    
+  
+  /*-------------------------------------------*/
+
+  /* Tidy up and exit */
+    
+  if (verboseflag == ON) 
+    fprintf(stderr, "\n");
+  fclose(inputfp); 
+  fclose(outputfigurefp); 
+ 
+  if ( ferror(inputfp) != 0) {
+    fprintf(stderr, " %s : error closing input file.\n", progname);
+    exit(-1);}
+
+  if ( ferror(outputfigurefp) != 0) {
+    fprintf(stderr, " %s : error closing figure file.\n", progname);
+    exit(-1);}
+
+  exit(0);
+
+} /* Main */
+
+
+
+
+
+
+/*---------------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+
+
+
+
+
+void parsecommandline(int argc, char *argv[], char inputfn[], char outputbasefn[])
+{
+  int x=1, helpflag = OFF;
+
+  while (x < argc){
+    if      (!strcmp(argv[x], "-o")) {strcpy(outputbasefn, argv[x+1]); x+=2;}
+    else if (!strcmp(argv[x], "-output")) {strcpy(outputbasefn, argv[x+1]); x+=2;}
+    else if (!strcmp(argv[x], "-i")) {strcpy(inputfn, argv[x+1]); x+=2;}
+    else if (!strcmp(argv[x], "-input")) {strcpy(inputfn, argv[x+1]); x+=2;}
+    else if (!strcmp(argv[x], "-help")) {helpflag = ON; x+=1;}
+    else if (!strcmp(argv[x], "-h")) {helpflag = ON; x+=1;}
+    else if (!strcmp(argv[x], "-verbose")) {verboseflag = ON; x+=1;}
+    else if (!strcmp(argv[x], "-v")) {verboseflag = ON; x+=1;}
+    else if (!strcmp(argv[x], "-weight")) {weightflag = NORMAL_WEIGHTING; x+=1;}
+    else if (!strcmp(argv[x], "-weightlog")) {weightflag = LOG_WEIGHTING; x+=1;}
+    else if (!strcmp(argv[x], "-width")) {widthflag = ON; total_width=atoi(argv[x+1]); x+=2;}
+    else if (!strcmp(argv[x], "-r")) { removeflag = ON; removevalue = atof(argv[x+1]); x+=2;}
+    else if (!strcmp(argv[x], "-a")) { asciiflag = ON;x+=1;}
+    else if (!strcmp(argv[x], "-ar")) { asciiflag = ON; asciireverseflag=ON; x+=1;}
+    else if (!strcmp(argv[x], "-s")) { summationflag=ON; x+=1;}
+    else if (!strcmp(argv[x], "-g")) { greyscaleflag=ON; x+=1;}
+    else if (!strcmp(argv[x], "-grey")) { greyscaleflag=ON; x+=1;}
+    else if (!strcmp(argv[x], "-gray")) { greyscaleflag=ON; x+=1;}
+    else if (!strcmp(argv[x], "-oparch")) { oppositearchflag=ON; x+=1;}
+    else {fprintf(stderr, "%s: unknown option %s\n", progname, argv[x]);
+	  exit(-1);}
+  }
+  
+  if (helpflag == ON)
+    {
+      fprintf(stderr, "\n");
+      fprintf(stderr, "                         %s\n", progname);
+      fprintf(stderr, " -----------------------------------------------------------------------------\n");
+      fprintf(stderr, " Works out a histogram of peak intervals, from a .sai\n");
+      fprintf(stderr, " Default output is a .sai file: if -a or -ar specified,\n");
+
+      fprintf(stderr, " then output is a ASCII matrix.\n");
+      fprintf(stderr, "\n");
+      fprintf(stderr, " The -oparch option is REQUIRED if reading a Sun .sai files \n");
+      fprintf(stderr, " on a DEC cpu or vice-versa.\n");
+      fprintf(stderr, " Add .sai to both input and output filenames.\n");
+
+      fprintf(stderr, " -----------------------------------------------------------------------------\n");
+      fprintf(stderr, "\n");
+      fprintf(stderr, " -i <.sai file>      input file             default = stdin\n");
+      fprintf(stderr, " -o <.sai file>      output file            default = stdout\n");
+      fprintf(stderr, " -oparch             assume input was generated on an opposing architecture\n");
+      fprintf(stderr, "\n");
+      fprintf(stderr, " -a                  ASCII output: rows = channels\n");
+      fprintf(stderr, " -ar                 ASCII output: rows = time intervals\n");
+      fprintf(stderr, " -s                  include summations over time intervals (ASCII options only)\n");
+      fprintf(stderr, "\n");
+      fprintf(stderr, " -width <int>        width of graph.sai (msecs).\n");
+      fprintf(stderr, " -r <fraction>       remove any peaks F(n) < F(n+1) & F(n-1) * fract \n");
+      fprintf(stderr, "                                            default = %.3f\n", removevalue);
+      fprintf(stderr, " -weight             weight histogram entries by mean height of peaks\n");
+      fprintf(stderr, " -weightlog          as per -weight, but use 10log(mean height)\n");
+      fprintf(stderr, "\n");
+      fprintf(stderr, " -v                  verbose output (to stderr)\n");
+      fprintf(stderr, " -g                  change .sai 'view' format to 'grayscale'.\n");
+      fprintf(stderr, "\n\n");
+      exit(-1);}
+
+}  
+
+
+
+
+/* The End */
+/*---------------------------------------------------------------------------*/