!!Stack= 0

c                                        
c	do_EMG_calc  
c
c	Copyright by Dwight Meglan 1990
c
c	Purpose:	Controlling routine that calls the EMG calculation 
c				routines
c
c	Routines called:
c		FilterEMG 
c		IntegrateEMG
c		MoveWinAvgEMG
c		RectifyEMG
c     ThresholdEMG
c
c	Common Block Variables USED by routine:
c	Block Name		Variable Name
c
c	None
c
c	Common Block Variables MODIFIED by routine:
c	Block Name		Variable Name
c
c	Param			EP.Name
c
      subroutine do_EMG_calc( CMND,EF,OF )
      implicit none
      include 'a_const.inc'

      include 'a_struct.inc'
      include 'a_prm.inc'
      include 'a_names.inc'
      include 'a_emg.inc'

      record /CmndLine/    CMND      
      record /emg_flag/    EF
      record /option_flag/ OF

      integer*4 i

      if ( CMND.CmndText(2) .eq. 'NAM' ) then ! set emg channel name
        if ( (CMND.CmndIntVal(3) .lt. 0) .or.
     &       (CMND.CmndIntVal(3) .gt. EP.NumChnl) ) goto 1000
        if ( CMND.NumCmnd .lt. 4 ) then
          EP.Name(CMND.CmndIntVal(3))= '                    '
        else
          i= CMND.CmndStart(4)
          EP.Name(CMND.CmndIntVal(3))= CMND.Text(1)(i:i+19)
        end if

      else if ( CMND.CmndText(2) .eq. 'FIL' ) then
        call FilterEMG( CMND,EF,OF )

      else if ( CMND.CmndText(2) .eq. 'REC' ) then
        call RectifyEMG( CMND,EF,OF )

      else if ( CMND.CmndText(2) .eq. 'INT' ) then
        call IntegrateEMG( CMND,EF,OF )
        
      else if ( CMND.CmndText(2) .eq. 'MWA' ) then
        call MoveWinAvgEMG( CMND,EF,OF )
                  
      else if ( CMND.CmndText(2) .eq. 'THR' ) then
        call ThresholdEMG( CMND,EF,OF )
                  
      else if ( CMND.CmndText(2) .eq. 'DEL' ) then
        call DeleteEMG( CMND,EF,OF )

      else if ( CMND.CmndText(2) .eq. 'MAX' ) then
        call FindEMGMax( CMND,EF,OF )

      else if ( CMND.CmndText(2) .eq. 'NRM' ) then
        call NormalizeEMG( CMND,EF,OF )

      else if ( CMND.CmndText(2) .eq. 'MOD' ) then
        call ModifyEMG( CMND,EF,OF )

      else       
        write(6,100)
        if ( OF.ToLog ) write(3,100)
100     format(' Error - Invalid EMG command.'/
     &         '         Valid commands are: NAMe FILter RECtifiy INTegrate'/
     &         '                             MovingWindowAverage THReshold'/
     &         '                             DELete findemgMAXimum NoRMalize'/
     &         '                             MODify')
      end if
      return           

1000  write(6,1005) CMND.CmndText(3),EP.NumChnl
      if ( OF.ToLog ) write(3,1005) CMND.CmndText(3),EP.NumChnl
1005  format(' Error - ',a3,' is an invalid EMG channel number.'/
     &       '         Valid channels are 1-',i2)
      return
      end             
c                                        
c	RectifyEMG  
c
c	Copyright by Dwight Meglan 1990
c
c	Purpose:	Rectify EMG signals
c
c	Routines called:
c
c	None
c
c	Common Block Variables USED by routine:
c	Block Name		Variable Name
c
c	Param			EP.NumChnl
c	Param			EP.NumSamples
c
c	Common Block Variables MODIFIED by routine:
c	Block Name		Variable Name
c
c	EMG				EMGData
c
      subroutine RectifyEMG( CMND,EF,OF )
      implicit none
      include 'a_const.inc'

      include 'a_struct.inc'
      include 'a_prm.inc'
      include 'a_emg.inc'

      record /CmndLine/    CMND
      record /emg_flag/    EF
      record /option_flag/ OF

      integer*4 chnl,i

      if ( EF.read ) then
        do chnl= 1, EP.NumChnl
          do i= 1, EP.NumSamples
            EMGData(i,chnl)= abs(EMGData(i,chnl))
          end do
        end do
        EF.rectified= .true.
        if ( EF.NumProcOps .lt. 5 ) then
          EF.NumProcOps= EF.NumProcOps + 1
          EF.ProcOp(EF.NumProcOps)= CMND.Text(1)(1:40)
        end if
      else
        write(6,100)
        if ( OF.ToLog ) write(3,100)
100     format(' Error- Emg data has not been read in yet')
      end if          
      return
      end
c                                        
c	IntegrateEMG  
c
c	Copyright by Dwight Meglan 1990
c
c	Purpose:	Do moving window integration on EMG signals.  Window
c				width can be specified (in msec). 
c           NOTE that the maximum magnitude of the integral is scaled such
c           that is the same as the maximum magnitude of the input emg signal
c           This makes easier to graph the before and after emg signals on the
c           same plot with the same scaling...
c
c	Routines called:
c
c	IntegrateData
c
c	Common Block Variables USED by routine:
c	Block Name		Variable Name
c
c	Param			EP.NumChnl
c	Param			EP.NumSamples
c	Param			EP.SampleRate
c
c	Common Block Variables MODIFIED by routine:
c	Block Name		Variable Name
c
c	EMG				EMGData
c
      subroutine IntegrateEMG( CMND,EF,OF )
      implicit none
      include 'a_const.inc'

      include 'a_struct.inc'
      include 'a_prm.inc'
      include 'a_emg.inc'

      record /CmndLine/    CMND
      record /emg_flag/    EF
      record /option_flag/ OF

      integer*4 chnl,i,j,WinIntWidth,Half1,Half2
      real*4    SampleTime,WinWidth,TimeInc,Data(MAX_EMF),
     &          DataInt(MAX_EMF),NewEMGData(MAX_EMF),MaxSignal,MaxIntegral,
     &          ratio

      if ( .not. EF.read ) goto 1000 ! error
c
c     check for window width (in msec) option
c
      SampleTime= 1000.0*float(EP.NumSamples)/float(EP.SampleRate)
      TimeInc= 1.0/float(EP.SampleRate)
      if ( CMND.NumOpt(2) .gt. 0 ) then
        if ( CMND.OptText(1,2) .eq. 'WIN' ) then
          if ( .not. CMND.OptNumOK(1,2) ) goto 1010
          if ( (CMND.OptRealVal(1,2) .le. 1.0) .or.
     &         (CMND.OptRealVal(1,2) .gt. SampleTime) ) goto 1010
          WinWidth= CMND.OptRealVal(1,2)
        else
          goto 1020
        end if
      else
        WinWidth= 50.0
        write(6,500)
500     format(' Default moving window width of 50 msec used')
      end if
      WinIntWidth= EP.NumSamples*(WinWidth/SampleTime)
      if ( WinIntWidth .lt. 1 ) then
        WinIntWidth= 1
      else if ( WinIntWidth .gt. EP.NumSamples ) then
        WinIntWidth= EP.NumSamples
      end if
      Half1= WinIntWidth/2
      Half2= WinIntWidth - Half1 - 1
      do chnl= 1, EP.NumChnl
        if ( OF.UpDate ) write(6,100) Chnl,EP.NumChnl
100     format('+ Filtering EMG Channel # ',i2,'/',i2)
        MaxSignal= abs(EMGData(1,chnl))
        do i= 2, EP.NumSamples
          if ( abs(EMGData(i,chnl)) .gt. MaxSignal ) 
     &      MaxSignal= abs(EMGData(i,chnl))
        end do
        do i= Half1, EP.NumSamples - Half2
          do j= 1, WinIntWidth
            Data(j)= EMGData(i-Half1+j,chnl)
          end do
          call IntegrateData( Data,WinIntWidth,TimeInc,DataInt )
          NewEMGData(i)= DataInt(WinIntWidth)
        end do
        do i= 1, Half1-1
          EMGData(i,chnl)= 0.0
        end do
        do i= Half1, EP.NumSamples - Half2
          EMGData(i,chnl)= NewEMGData(i)
        end do
        do i= EP.NumSamples - Half2 + 1, EP.NumSamples
          EMGData(i,chnl)= 0.0
        end do
        MaxIntegral= abs(EMGData(1,chnl))
        do i= 2, EP.NumSamples
          if ( abs(EMGData(i,chnl)) .gt. MaxIntegral ) 
     &      MaxIntegral= abs(EMGData(i,chnl))
        end do
        ratio= MaxSignal/MaxIntegral
        do i= 1, EP.NumSamples
          EMGData(i,chnl)= EMGData(i,chnl)*ratio
        end do
      end do ! chnl
      EF.Integrated= .true.
      if ( EF.NumProcOps .lt. 5 ) then
        EF.NumProcOps= EF.NumProcOps + 1
        EF.ProcOp(EF.NumProcOps)= CMND.Text(1)(1:40)
      end if
      return
      
1000  write(6,1005)
      if ( OF.ToLog ) write(3,1005)
1005  format(' Error- Emg data has not been read in yet')
      return

1010  write(6,1015) CMND.OptRealVal(1,2),SampleTime
      if ( OF.ToLog ) write(3,1015) CMND.OptRealVal(1,2),SampleTime
1015  format(' Error- ',f10.4,' is not a valid integration window width'/
     &       '        Valid windows are >1.0 msec and <',f10.4,' msec')
      return
      
1020  write(6,1025) CMND.OptText(1,2)
      if ( OF.ToLog ) write(3,1025) CMND.OptText(1,2)
1025  format(' Error- ',a3,' is not a valid integration option'/
     &       '        Only valid option is /WIN=size (msec)')
      return
      end
c                                        
c	MoveWinAvgEMG  
c
c	Copyright by Dwight Meglan 1990
c
c	Purpose:	Do moving window averaging on EMG signals.  Window
c				width can be specified (in msec).  Also, a cosine
c				weighting function can be applied to the window.
c
c	Routines called:
c
c	None
c
c	Common Block Variables USED by routine:
c	Block Name		Variable Name
c
c	Param			EP.NumChnl
c	Param			EP.NumSamples
c	Param			EP.SampleRate
c
c	Common Block Variables MODIFIED by routine:
c	Block Name		Variable Name
c
c	EMG				EMGData
c
      subroutine MoveWinAvgEMG( CMND,EF,OF )
      implicit none
      include 'a_const.inc'

      include 'a_struct.inc'
      include 'a_prm.inc'
      include 'a_emg.inc'

      record /CmndLine/    CMND
      record /emg_flag/    EF
      record /option_flag/ OF

      integer*4 chnl,i,j,WinIntWidth,Half1,Half2,pi
      real*4    SampleTime,WinWidth,TimeInc,NewEMGData(MAX_EMF)
      logical*4 UseTaper
                          
      if ( .not. EF.read ) goto 1000 ! error
c
c     check for window width (in msec) and cosine taper options
c
      SampleTime= 1000.0*float(EP.NumSamples)/float(EP.SampleRate)
      UseTaper= .false.
      if ( CMND.NumOpt(2) .gt. 0 ) then
        do i= 1, CMND.NumOpt(2)
          if ( CMND.OptText(i,2) .eq. 'WIN' ) then
            if ( .not. CMND.OptNumOK(i,2) ) goto 1010
            if ( (CMND.OptRealVal(i,2) .le. 1.0) .or.
     &           (CMND.OptRealVal(i,2) .gt. SampleTime) ) goto 1010
            WinWidth= CMND.OptRealVal(i,2)
          else if ( CMND.OptText(i,2) .eq. 'COS' ) then
            UseTaper= .true.
          else
            goto 1020
          end if
        end do
      else
        WinWidth= 50.0
        write(6,500)
500     format(' Default moving window width of 50 msec used')
      end if
      WinIntWidth= EP.NumSamples*(WinWidth/SampleTime)
      if ( WinIntWidth .lt. 1 ) then
        WinIntWidth= 1
      else if ( WinIntWidth .gt. EP.NumSamples ) then
        WinIntWidth= EP.NumSamples
      end if
      Half1= WinIntWidth/2
      Half2= WinIntWidth - Half1 - 1
c
c     DO the moving average
c
      pi= 4.0*atan(1.0)
      do chnl= 1, EP.NumChnl
        if ( OF.UpDate ) write(6,100) Chnl,EP.NumChnl
100     format('+ Averaging EMG Channel # ',i2,'/',i2)
        do i= Half1, EP.NumSamples - Half2
          NewEMGData(i)= 0.0
          if ( UseTaper ) then
            do j= 1, WinIntWidth
              NewEMGData(i)= NewEMGData(i) + EMGData(i-Half1+j,chnl)*
     &          cos( -pi/2.0 + pi*float(j-1)/float(WinIntWidth-1) )
            end do
            NewEMGData(i)= NewEMGData(i)/float(WinIntWidth)
          else
            do j= 1, WinIntWidth
              NewEMGData(i)= NewEMGData(i) + EMGData(i-Half1+j,chnl)
            end do
            NewEMGData(i)= NewEMGData(i)/float(WinIntWidth)
          end if
        end do
        do i= 1, Half1-1
          EMGData(i,chnl)= 0.0
        end do
        do i= Half1, EP.NumSamples - Half2
          EMGData(i,chnl)= NewEMGData(i-Half1+j)
        end do
        do i= EP.NumSamples - Half2 + 1, EP.NumSamples
          EMGData(i,chnl)= 0.0
        end do
      end do ! chnl
      if ( EF.NumProcOps .lt. 5 ) then
        EF.NumProcOps= EF.NumProcOps + 1
        EF.ProcOp(EF.NumProcOps)= CMND.Text(1)(1:40)
      end if
      EF.Averaged= .true.
      return
      
1000  write(6,1005)
      if ( OF.ToLog ) write(3,1005)
1005  format(' Error- Emg data has not been read in yet')
      return

1010  write(6,1015) CMND.OptRealVal(1,2),SampleTime
      if ( OF.ToLog ) write(3,1015) CMND.OptRealVal(1,2),SampleTime
1015  format(' Error- ',f10.4,' is not a valid integration window width'/
     &       '        Valid windows are >1.0 msec and <',f10.4,' msec')
      return
      
1020  write(6,1025) CMND.OptText(i,2)
      if ( OF.ToLog ) write(3,1025) CMND.OptText(i,2)
1025  format(' Error- ',a3,' is not a valid integration option'/
     &       '        Valid options are: /WIN=size (msec)  /COS')
      return
      end
c                                        
c	ThresholdEMG  
c
c	Copyright by Dwight Meglan 1990
c
c	Purpose:	Do thresholding on EMG signals.  This is intended primarily to
c				be used with emg signals that have at least been rectified and
c			   probably integrated or averaged or digtially low pass filtered.
c           Essentially all it does is scan each emg for the maximum signal
c           strength and then say that if the signal is above a specified
c           percentage of this, then the muscle is active otherwise it is not.
c           The active state is represented by a 1 and inactive by 0.  NOTE
c           that this is a VERY simple minded way of saying muscle on/off and
c           it completely destroys the emg data since it is replaced with 0/1
c           There are much more sophisticated techniques published which should
c           be investigated as an alternative to this
c
c	Routines called:
c
c	None
c
c	Common Block Variables USED by routine:
c	Block Name		Variable Name
c
c	Param			EP.NumChnl
c	Param			EP.NumSamples
c	Param			EP.SampleRate
c
c	Common Block Variables MODIFIED by routine:
c	Block Name		Variable Name
c
c	EMG				EMGData
c
      subroutine ThresholdEMG( CMND,EF,OF )
      implicit none
      include 'a_const.inc'

      include 'a_struct.inc'
      include 'a_prm.inc'
      include 'a_emg.inc'

      record /CmndLine/    CMND                 
      record /emg_flag/    EF
      record /option_flag/ OF     

      integer*4 chnl,frm,i
      real*4    Percent,MaxSignal,OnSignal
c
c     /PERcent of maximum option
c
      if ( .not. EF.Rectified ) goto 1000 ! error
      Percent= 20.0
      if ( CMND.NumOpt(2) .gt. 0 ) then
        do i= 1, CMND.NumOpt(2)
          if ( CMND.OptText(i,2) .eq. 'PER' ) then
            if ( .not. CMND.OptNumOK(i,2) ) goto 1010
            if ( (CMND.OptRealVal(i,2) .le. 0.0) .or.
     &           (CMND.OptRealVal(i,2) .gt. 100.0) ) goto 1010
            Percent= CMND.OptRealVal(i,2)
          else    
            goto 1020
          end if
        end do                
      else
        write(6,500)
500     format(' Default 20.0% of maximum signal threshold used'/)
      end if
c
c     Do the thresholding
c
      do chnl= 1, EP.NumChnl
        if ( OF.UpDate ) write(6,100) Chnl,EP.NumChnl
100     format('+ Thresholding EMG Channel # ',i2,'/',i2)
        MaxSignal= EMGData(1,chnl)
        do frm= 2, EP.NumSamples
          if ( EMGData(frm,chnl) .gt. MaxSignal ) MaxSignal= EMGData(frm,chnl)
        end do
        OnSignal= MaxSignal/2.0
        MaxSignal= Percent*MaxSignal/100.0
        do frm= 1, EP.NumSamples
          if ( EMGData(frm,chnl) .ge. MaxSignal ) then
            EMGData(frm,chnl)= OnSignal
          else
            EMGData(frm,chnl)= 0.0
          end if
        end do
      end do ! chnl
      if ( EF.NumProcOps .lt. 5 ) then
        EF.NumProcOps= EF.NumProcOps + 1
        EF.ProcOp(EF.NumProcOps)= CMND.Text(1)(1:40)
      end if
      return

1000  write(6,1005)
      if ( OF.ToLog ) write(3,1005)
1005  format(' Error- Emg data has not been rectified yet')
      return

1010  write(6,1015) CMND.OptRealVal(1,2)
      if ( OF.ToLog ) write(3,1015) CMND.OptRealVal(1,2)
1015  format(' Error- ',f10.4,' is not a valid percent of maximum signal'/
     &       '        Valid percentages are from 1 to 100%')
      return
      
1020  write(6,1025) CMND.OptText(i,2)
      if ( OF.ToLog ) write(3,1025) CMND.OptText(i,2)
1025  format(' Error- ',a3,' is not a valid integration option'/
     &       '        Valid options are: /PERcent=#')
      return
      end                                                 
c                                        
c	DeleteEMG  
c
c	Copyright by Dwight Meglan 1990
c
c	Purpose:	Delete selected channels of EMG data from that read in.  This is
c           an auxillary function to save disk space for the data runs where
c           EMG data was inadvertantly taken with force plate data and in
c           reality on EMG's were hooked up.
c
c	Routines called:
c
c	None
c
c	Common Block Variables USED by routine:
c	Block Name		Variable Name
c
c	Param			EP.NumSamples
c	Param			EP.SampleRate
c
c	Common Block Variables MODIFIED by routine:
c	Block Name		Variable Name
c
c	Param			   EP.CodeNum
c	Param			   EP.Name
c	Param			   EP.NumChnl
c	Param			   EP.Surface
c	EMG				EMGData
c                                
      subroutine DeleteEMG( CMND,EF,OF )
      implicit none
      include 'a_const.inc'
                     
      include 'a_struct.inc'
      include 'a_prm.inc'
      include 'a_emg.inc'

      record /CmndLine/    CMND                 
      record /emg_flag/    EF
      record /option_flag/ OF     

      integer*4 chnl,i,j,NumDelChnl,DelChnl(MAX_EMG)
              
      if ( .not. EF.read ) goto 1000
c
c     Determine channel #
c                         
      if ( CMND.NumCmnd .lt. 3 ) goto 1010
      if ( CMND.CmndText(3) .eq. 'ALL' ) then
        EP.NumChnl= 0
      else                    
        NumDelChnl= 0
        do i= 3, CMND.NumCmnd
          if ( .not. CMND.CmndNumOK(i) ) goto 1020  
          if ( (CMND.CmndIntVal(i) .lt. 1) .or. 
     &         (CMND.CmndIntVal(i) .gt. EP.NumChnl) ) goto 1020
          DelChnl(i-2)= CMND.CmndIntVal(i)
          NumDelChnl= NumDelChnl + 1
        end do              
c                            
c       Sort channels in ascending order
c                         
        if ( NumDelChnl .gt. 1 ) call PickSortInt( NumDelChnl,DelChnl )
        do i= NumDelChnl, 1
          chnl= DelChnl(i)
          if ( chnl .lt. MAX_EMG ) then
            EP.CodeNum(chnl)= EP.CodeNum(chnl+1)
            EP.Name(chnl)=    EP.Name(chnl+1)
            EP.Surface(chnl)= EP.Surface(chnl+1)
            do j= 1, EP.NumSamples
              EMGData(j,chnl)= EMGData(j,chnl+1)
            end do
          end if
          EP.NumChnl= EP.NumChnl - 1
        end do
      end if ! delete all or just some channels
      return

1000  write(6,1005)
      if ( OF.ToLog ) write(3,1005)
1005  format(' Error- Emg data has not been read yet')
      return                                                              
                                    
1010  write(6,1015) 
      if ( OF.ToLog ) write(3,1015) 
1015  format(' Error- There must be at least 3 entries for EMG DELete #')
      return
      
1020  write(6,1025) CMND.CmndText(i),EP.NumChnl
      if ( OF.ToLog ) write(3,1025) CMND.CmndText(i),EP.NumChnl
1025  format(' Error- ',a3,' is not a valid channel number'/
     &       '        Valid channels are 1 to ',i2,' and ALL')
      return
      end
c                         
c     From Numerical Recipes p. 227 - modified to use structured fortran
c        
      subroutine PickSortInt( N,Array )
      implicit none
                                                 
      integer*4 N,Array(1),i,j,a
                                                 
      do j= 2, N
        a= Array(j)
        i= j-1
        do while ( (i .ge. 1) .and. (Array(i) .gt. a) )
          Array(i+1)= Array(i)
          i= i - 1
        end do
        if ( i .eq. 1 ) i= 0
        Array(i+1)= a
      end do               
      return
      end
c              
c	FindEMGMax
c
c	Copyright by Dwight Meglan 1992
c
c	Purpose:	Find the maximum value of the EMG signals
c
c	Routines called:        
c
c	None
c
c	Common Block Variables USED by routine:
c	Block Name		Variable Name
c
c	Param			EP.NumChnl
c	Param			EP.NumSamples
c
c	Common Block Variables MODIFIED by routine:
c	Block Name		Variable Name
c
c	EMG				EMGData
c  Param          EP.CodeNum
c
      subroutine FindEMGMax( CMND,EF,OF )
      implicit none
      include 'a_const.inc'

      include 'a_struct.inc'
      include 'a_prm.inc'
      include 'a_emg.inc'

      record /CmndLine/    CMND
      record /emg_flag/    EF
      record /option_flag/ OF

      integer*4 chnl,i
      real*4    max
      logical*4 IgnoreNegVal

      if ( EF.read ) then
        IgnoreNegVal= .false.
        if ( CMND.NumOpt(2) .gt. 0 ) then
          if ( CMND.OptText(1,2) .eq. 'NON' ) then
            IgnoreNegVal= .true.
          else
            write(6,100) CMND.OptText(1,2)
            if ( OF.ToLog ) write(3,100) CMND.OptText(1,2)
100         format(' ERROR- ',a3,' is not a valid option'/
     &             '        The only valid option is /NONegative values')
            return
          end if       
        end if
        do chnl= 1, EP.NumChnl
          max= 0.0
          if ( IgnoreNegVal ) then
            do i= 1, EP.NumSamples
              if ( EMGData(i,chnl) .gt. max ) max= EMGData(i,chnl)
            end do
            if ( max .lt. 1.0e-6 )  max= 1.0
          else
            do i= 1, EP.NumSamples
              if ( abs(EMGData(i,chnl)) .gt. max ) max= abs(EMGData(i,chnl))
            end do
          end if
          EP.CodeNum(chnl)= max*1000.0
        end do     
        EF.maximum= .true.
        if ( EF.NumProcOps .lt. 5 ) then
          EF.NumProcOps= EF.NumProcOps + 1
          EF.ProcOp(EF.NumProcOps)= CMND.Text(1)(1:40)
        end if
      else             
        write(6,110)
        if ( OF.ToLog ) write(3,110)
110     format(' Error- Emg data has not been read in yet')
      end if          
      return
      end
c              
c	NormalizeEMG
c
c	Copyright by Dwight Meglan 1992
c
c	Purpose: Normalize the EMG signals relative to either:
c           a) The maximums previously calculated with the EMG MAX command
c           b) Manually input values
c           Multiple channels may be specified in the manual mode and the 
c           command may given multiple times to normalize all the channels
c           There is no requirement in the manual mode that all channels be
c           normalized. When the maximums are used, all channels are normalized.
c
c	Routines called:        
c
c	None
c
c	Common Block Variables USED by routine:
c	Block Name		Variable Name
c
c	Param			EP.NumChnl
c	Param			EP.NumSamples
c  Param       EP.CodeNum
c
c	Common Block Variables MODIFIED by routine:
c	Block Name		Variable Name
c
c	EMG				EMGData
c
      subroutine NormalizeEMG( CMND,EF,OF )
      implicit none           
      include 'a_const.inc'

      include 'a_struct.inc'
      include 'a_prm.inc'
      include 'a_emg.inc'

      record /CmndLine/    CMND
      record /emg_flag/    EF
      record /option_flag/ OF

      integer*4 chnl,i                        
      real*4    NormVal(MAX_EMG)
                                       
      if ( .not. EF.read ) goto 1000
c
c     Decide whether to use the internally stored EMG maximums or to use
c     the values manually input on the command line
c
      if ( CMND.NumOpt(2) .gt. 0 ) then
        if ( CMND.OptText(1,2) .eq. 'MAX' ) then
          if ( .not. EF.Maximum ) goto 1010
          do i= 1, EP.NumChnl
            NormVal(i)= float(EP.CodeNum(i))/1000.0
          end do
        else
          goto 1020
        end if
      else ! scan for manually input normalization values
        do i= 1, MAX_EMG
          NormVal(i)= 1.0
        end do
        do i= 3, CMND.NumCmnd,2 ! look at pairs of numbers
          chnl= CMND.CmndIntVal(i)
          if ( (chnl .gt. 0) .and. (chnl .le. MAX_EMG) ) then
            if ( CMND.CmndNumOK(i+1) ) then
              NormVal(chnl)= CMND.CmndRealVal(i+1)
            else
              goto 1030 ! bad normalization value
            end if
          else
            goto 1040 ! bad emg channel number
          end if
        end do
      end if                        
c
c    Normalize the EMG signals
c
      do chnl= 1, EP.NumChnl
        if ( abs(NormVal(chnl)) .lt. 1.0e-6 ) then
          write(6,100) chnl                        
          if ( OF.ToLog ) write(3,100) chnl
100       format(' NOTE- The normalization value for channel ',i2,' is very ',
     &           'small'/'       This channel is not being normalized')
        else
          EP.CodeNum(chnl)= NormVal(chnl)*1000.0
          do i= 1, EP.NumSamples              
            EMGData(i,chnl)= EMGData(i,chnl)/NormVal(chnl)
          end do
        end if
      end do     
      EF.normalized= .true.
      if ( EF.NumProcOps .lt. 5 ) then
        EF.NumProcOps= EF.NumProcOps + 1
        EF.ProcOp(EF.NumProcOps)= CMND.Text(1)(1:40)
      end if
      return

1000  write(6,1005)
      if ( OF.ToLog ) write(3,1005)
1005  format(' Error- Emg data has not been read in yet')
      return

1010  write(6,1015)
      if ( OF.ToLog ) write(3,1015)
1015  format(' Error- EMG maximums have not been calculated so it is not'/
     &       '        possible to normalize the EMG signals with the /MAX option')
      return

1020  write(6,1025) CMND.OptText(1,2)
      if ( OF.ToLog ) write(3,1025) CMND.OptText(1,2)
1025  format(' Error- ',a3,' is not a valid option for EMG NoRaMalization'/
     &       '        The only valid option is /MAXimum')
      return
    
1030  write(6,1035) CMND.CmndText(i+1),chnl
      if ( OF.ToLog ) write(3,1035) CMND.CmndText(i+1),chnl
1035  format(' Error- ',a3,' is not a valid normalization value for channel',i2)
      return

1040  write(6,1045) CMND.CmndText(i),EP.NumChnl
      if ( OF.ToLog ) write(3,1045) CMND.CmndText(i),EP.NumChnl
1045  format(' Error- ',a3,' is not a valid emg channel number'/
     &       '        Valid channels are 1 thru ',i2)
      return
      end

    
c              
c	ModifyEMG
c
c	Copyright by Dwight Meglan 1992
c
c	Purpose: Modify the EMG signal. Presently there are four operations:
c           a) Cut out the frames from BEGin frame to END frame and REPlace
c              the signal with the average of frames from ABE to AEN
c           b) ZERo the signal relative to either the MINimum value in the 
c              signal or the average of frames ABE to AEN
c           c) Set all negative values to 0.0 (NON)
c           d) ADD a value to individual emg signals
c
c	Routines called:        
c
c	None
c
c	Common Block Variables USED by routine:
c	Block Name		Variable Name
c
c	Param			EP.NumChnl
c	Param			EP.NumSamples
c  Param       EP.CodeNum
c
c	Common Block Variables MODIFIED by routine:
c	Block Name		Variable Name
c
c	EMG				EMGData
c                                   
      subroutine ModifyEMG( CMND,EF,OF )
      implicit none           
      include 'a_const.inc'

      include 'a_struct.inc'
      include 'a_prm.inc'
      include 'a_emg.inc'

      record /CmndLine/    CMND
      record /emg_flag/    EF
      record /option_flag/ OF                   

      integer*4 chnl(MAX_EMG),i,j,NumOpt,BeginFrm,EndFrm,AvgBeginFrm,AvgEndFrm,
     &          numchnl,frm
      real*4    AvgVal,MinVal,EMGAddVal(MAX_EMG)
      character Option(9)*3
      logical*4 Replace,ZeroEMG,NoNegVal,UseMinSignal,OptOK,AddVal
                                         
      data NumOpt / 9 /
      data Option / 'REP','ZER','NON','ADD','BEG','END','ABE','AEN','MIN' /
                                                     
      if ( .not. EF.read ) goto 1000
c                            
c     Check Options and decid which of the three primary options are to be
c     carried out
c
      if ( CMND.NumOpt(2) .gt. 0 ) then
        Replace=  .false.
        ZeroEMG=  .false.
        NoNegVal= .false.
        AddVal=   .false.
        UseMinSignal= .false.
        BeginFrm= 1
        EndFrm= 20
        AvgBeginFrm= 21
        AvgEndFrm= 30
        do i= 1, CMND.NumOpt(2)
          OptOK= .false.
          do j= 1, NumOpt
            if ( CMND.OptText(i,2) .eq. Option(j) ) OptOK= .true.
          end do
          if ( .not. OptOK ) goto 1010                     
          if ( CMND.OptText(i,2) .eq. 'REP' ) then 
            Replace= .true.
          else if ( CMND.OptText(i,2) .eq. 'ZER' ) then
            ZeroEMG= .true.
          else if ( CMND.OptText(i,2) .eq. 'NON' ) then
            NoNegVal= .true.
          else if ( CMND.OptText(i,2) .eq. 'ADD' ) then
            AddVal= .true.
          else if ( CMND.OptText(i,2) .eq. 'MIN' ) then
            UseMinSignal= .true.
          else if ( CMND.OptText(i,2) .eq. 'BEG' ) then
            BeginFrm= CMND.OptIntVal(i,2)
            if ( (BeginFrm .lt. 1) .or. (BeginFrm .gt. EP.NumSamples) ) goto 1030
          else if ( CMND.OptText(i,2) .eq. 'END' ) then
            EndFrm= CMND.OptIntVal(i,2)
            if ( (EndFrm .lt. 1) .or. (EndFrm .gt. EP.NumSamples) ) goto 1040
          else if ( CMND.OptText(i,2) .eq. 'ABE' ) then
            AvgBeginFrm= CMND.OptIntVal(i,2)
            if ( (AvgBeginFrm .lt. 1) .or. 
     &           (AvgBeginFrm .gt. EP.NumSamples) ) goto 1050
          else if ( CMND.OptText(i,2) .eq. 'AEN' ) then
            AvgEndFrm= CMND.OptIntVal(i,2)
            if ( (AvgEndFrm .lt. 1) .or. 
     &           (AvgEndFrm .gt. EP.NumSamples) ) goto 1060
          end if
        end do
      else     
        goto 1020    
      end if                              
      if ( EndFrm .le. BeginFrm ) goto 1070
      if ( AvgEndFrm .le. AvgBeginFrm ) goto 1080
c
c     Made it through the determination of the options, now figure out
c     which channels to operate upon...
c
      numchnl= 0
      if ( CMND.CmndText(3) .eq. 'ALL' ) then
        numchnl= EP.NumChnl
        do i= 1, numchnl
          chnl(i)= i                                   
        end do
        if ( AddVal ) then
          if ( .not. CMND.CmndNumOK(4) ) goto 1110 
          do i= 1, numchnl
            EMGAddVal(i)= CMND.CmndRealVal(4)
          end do
        end if
      else
        if ( AddVal ) then
          do i= 3, CMND.NumCmnd,2
            if ( (CMND.CmndIntVal(i) .gt. 1) .and. 
     &           (CMND.CmndIntVal(i) .le. EP.NumChnl) ) then
              numchnl= numchnl + 1
              chnl(numchnl)= CMND.CmndIntVal(i)
              if ( .not. CMND.CmndNumOK(i+1) ) goto 1120
              EMGAddVal(numchnl)= CMND.CmndRealVal(i+1)
            else
              goto 1090
            end if
          end do
        else
          do i= 3, CMND.NumCmnd
            if ( (CMND.CmndIntVal(i) .gt. 1) .and. 
     &           (CMND.CmndIntVal(i) .le. EP.NumChnl) ) then
              numchnl= numchnl + 1
              chnl(numchnl)= CMND.CmndIntVal(i)
            else
              goto 1090
            end if
          end do
        end if
        if ( numchnl .eq. 0 ) goto 1100
      end if
c
c     Decisions have all been made now modify the EMG signals
c
c     Replace the frames from BEGin to END with the average of ABEgin to 
c     AENd frames
c
      if ( Replace ) then
        write(6,100) BeginFrm,EndFrm,AvgBeginFrm,AvgEndFrm
        if ( OF.ToLog ) 
     &    write(3,100) BeginFrm,EndFrm,AvgBeginFrm,AvgEndFrm
100     format(' NOTE- Replacing EMG signals from frame ',i4,' to ',i4,/
     &         '       with the average of frames ',i4,' to ',i4)
        do i= 1, numchnl
          j= chnl(i)
          AvgVal= 0.0
          do frm= AvgBeginFrm, AvgEndFrm
            AvgVal= AvgVal + EMGData(frm,j)
          end do
          AvgVal= AvgVal/float(AvgEndFrm-AvgBeginFrm+1)
          do frm= BeginFrm, EndFrm
            EMGData(frm,j)= AvgVal
          end do
        end do
      end if
c
c     Zero the EMG signals
c
      if ( ZeroEMG ) then
        if ( UseMinSignal ) then                       
          write(6,110) 
          if ( OF.ToLog ) write(3,110) 
110       format(' NOTE- Zeroing EMG signals with minimum of data')
          do i= 1, numchnl
            j= chnl(i)              
            MinVal= EMGData(1,j)
            do frm= 2, EP.NumSamples
              if ( EMGData(frm,j) .lt. MinVal ) MinVal= EMGData(frm,j)
            end do
            do frm= 1, EP.NumSamples
              EMGData(frm,j)= EMGData(frm,j) - MinVal
            end do
          end do                                         
        else
          write(6,120) AvgBeginFrm,AvgEndFrm
          if ( OF.ToLog ) write(3,120) AvgBeginFrm,AvgEndFrm
120       format(' NOTE- Zeroing EMG signals with average of frames ',i4,' to ',i4)
          do i= 1, numchnl
            j= chnl(i)              
            AvgVal= 0.0
            do frm= AvgBeginFrm, AvgEndFrm
              AvgVal= AvgVal + EMGData(frm,j)
            end do
            AvgVal= AvgVal/float(AvgEndFrm-AvgBeginFrm+1)
            do frm= 1, EP.NumSamples
              EMGData(frm,j)= EMGData(frm,j) - AvgVal
            end do
          end do                           
        end if
      end if
c
c     Make all negative values equal to 0.0
c
      if ( NoNegVal ) then
        write(6,130)
        if ( OF.ToLog ) write(3,130)
130     format(' NOTE- Removing all negative EMG values')
        do i= 1, numchnl
          j= chnl(i)
          do frm= 1, EP.NumSamples
            if ( EMGData(frm,j) .lt. 0.0 ) EMGData(frm,j)= 0.0
          end do
        end do
      end if
c
c     Add a value to individual or all emg signals
c
      if ( AddVal ) then
        write(6,140) 
        if ( OF.ToLog ) write(3,140) 
140     format(' NOTE- Adding specified values to EMG signals')
        do i= 1, numchnl
          j= chnl(i)
          do frm= 1, EP.NumSamples
            EMGData(frm,j)= EMGData(frm,j) + EMGAddVal(i)
          end do
        end do
      end if
      return

1000  write(6,1005)
      if ( OF.ToLog ) write(3,1005)
1005  format(' Error- Emg data has not been read in yet')
      return
   
1010  write(6,1015) CMND.OptText(i,2)
      if ( OF.ToLog ) write(3,1015) CMND.OptText(i,2)
1015  format(' Error- ',a3,' is not a valid option for EMG MODify'/
     &       '        The valid options are: REPlace ZERo NONegativevalues'/
     &       '                               BEGinframe ENDframe useMINimum'/
     &       '                               AverageBEginframe AverageENdframe'/
     &       '                               ADDvalue'/)
      return
                                     
1020  write(6,1025)
      if ( OF.ToLog ) write(3,1025)
1025  format(' Error- EMG MODify command must have an option to indicate which'/
     &       '        operation will carried on the EMG signal(s)'/
     &       '        Present operations are: REPlace ZERo NONegative ADDvalue')
      return

1030  write(6,1035) CMND.OptText(i,2),EP.NumSamples
      if ( OF.ToLog ) write(3,1035) CMND.OptText(i,2),EP.NumSamples
1035  format(' Error- ',a3,' is not a valid beginning frame number'/
     &       '        Valid frame numbers are from 1 to ',i4)
      return

1040  write(6,1045) CMND.OptText(i,2),EP.NumSamples
      if ( OF.ToLog ) write(3,1045) CMND.OptText(i,2),EP.NumSamples
1045  format(' Error- ',a3,' is not a valid ending frame number'/
     &       '        Valid frame numbers are from 1 to ',i4)
      return

1050  write(6,1055) CMND.OptText(i,2),EP.NumSamples
      if ( OF.ToLog ) write(3,1055) CMND.OptText(i,2),EP.NumSamples
1055  format(' Error- ',a3,' is not a valid average section beginning frame number'/
     &       '        Valid frame numbers are from 1 to ',i4)
      return

1060  write(6,1065) CMND.OptText(i,2),EP.NumSamples
      if ( OF.ToLog ) write(3,1065) CMND.OptText(i,2),EP.NumSamples
1065  format(' Error- ',a3,' is not a valid average section ending frame number'/
     &       '        Valid frame numbers are from 1 to ',i4)
      return

1070  write(6,1075) EndFrm,BeginFrm
      if ( OF.ToLog ) write(3,1075) EndFrm,BeginFrm
1075  format(' Error- End Frame (',i4,') must be greater than begin frame (',
     &                i4,')')
      return

1080  write(6,1085) AvgEndFrm,AvgBeginFrm
      if ( OF.ToLog ) write(3,1085) AvgEndFrm,AvgBeginFrm
1085  format(' Error- End Frame (',i4,') of average section must be greater'/
     &       '        than begin frame (',i4,')')
      return                               

1090  write(6,1095) CMND.CmndText(i),EP.NumChnl
      if ( OF.ToLog ) write(3,1095) CMND.CmndText(i),EP.NumChnl
1095  format(' Error- ',a3,' is not a valid EMG channel number'/
     &       '        Valid channel numbers are: ALL and 1 to ',i2)
      return

1100  write(6,1105) 
      if ( OF.ToLog ) write(3,1105)
1105  format(' Error- The numbers of the EMG channels to be modified must be'/
     &       '        given in the EMG MODify command. The correct syntax is'/
     &       '        EMG MOD/OPT CHNL1 CHNL2 CHNL3 and so on...')
      return

1110  write(6,1115) CMND.CmndText(4)
      if ( OF.ToLog ) write(3,1115) CMND.CmndText(4)
1115  format(' Error- ',a3,' is not a valid number for adding to ALL channels')
      return

1120  write(6,1125) CMND.CmndText(i+1),chnl(numchnl)
      if ( OF.ToLog ) write(3,1125) CMND.CmndText(i+1),chnl(numchnl)
1125  format(' Error- ',a3,' is not a valid number for adding to channel # ',i2)
      return
      end
                                           
    
                                                               
