Cluster Analysis Documentation

advertisement
Cluster Analysis Documentation
The cluster program is designed to analyze unit activity in a histogram in a manner similar to how
our eyes perceive changes in activity. Chapter A (Cluster analysis) discusses this method with examples
as a possible solution to the problem of relating unit activity to behavior. Like the other programs
presented here this program also is written in Forth, but unlike the other programs it is written in the
version of Forth for Windows 3.1 from Laboratory Microsystems Inc (the earlier DOS version is
Micromotion's MasterForth). Much of the programming that is unfamiliar is related to controlling window
displays.
There are actually two programs here in this appendix. The dave.txt program is an
implementation of the Summary's Review routine. Like that review routine, dave.txt displays data from a
data disk on a trial-by-trial basis and allows for averaging trials together. In fact, with some minor but
important formatting differences, the DOS version of Forth was directly imported to the Windows version.
An additional feature of dave.txt is that it implements the cluster analysis program for two kinds of
displays: for unit histograms, significant unit clusters are filled whereas nonsignificant clusters are open
figures; for unit clusters per se, a frequency display is created for a block of trials. Both of these displays
have been illustrated in Chapter A (Cluster analysis). The second program is cluster.txt which gives a
detailed printout (or file) on a trial-by-trial basis of all the clusters. There are a number of different options,
described below in the documentation, for the type of information printed. The two most useful types of
information are the onset latency of the cluster and the frequency of the cluster. As we discuss below,
however, this cluster analysis is only a prelude to further statistics which relate consistency and strength of
responding between unit activity and behavior.
One of the advantages of the Laboratory Microsystems version of Forth is that the source code
files are text files which can be edited with any ASCII word processor. A big difference between the
Laboratory Microsystems and the Micromotion's MasterForth versions is that the latter uses the traditional
screen structure, whereas the former can use either the screen structure or the free format that we have
used. Thus, there are no references to the screeen in the two cluster programs that follow. A minor
difference related to this lack of screen structure is that almost all of our comments are placed within
parentheses. There are other differences in the implementation of the languages that we will not go into
detail but will be obvious to the reader (for example, the Windows version uses equ to change the value of
variables and switches). Finally, it should be noted that the cluster program is not that difficult to
implement, and there is no reason why one could not reverse the direction and import the essence of the
Windows cluster analysis program to the DOS version.
The formal documentation for loading and using the cluster programs follows. This
documentation begins with an introduction to the problem of analyzing unit activity, particularly with regard
to independently and consistently determining the latency of the activity. Next, a cluster is defined and the
analysis is discussed. Described next are how to load the programs and use the options for the print outs.
A nice feature about the Windows version is that, instead of printing out a hard copy, the information can
be printed to disk. This feature is potentially useful for exporting the information to a spreadsheet. Finally,
the assumptions of the cluster program are explicitly identified. This is useful for interpreting the cluster
results and for comparison with other methods. Following this documentation are the actual source files
for dave.txt and cluster.txt which make up the bulk of this appendix.
Cluster Analysis Documentation
Introduction
The cluster analysis software is designed to analyze unit activity that has been collected with our
forth Runtime/Summary programs. The purpose of this analysis is to identify the latency and magnitude of
unit activity during each trial of classical conditioning and to determine if that activity is significantly
different from baseline activity. The results are displayed to screen or printed out.
Background on data representation
To understand this analysis one needs to know just a little bit about how data is represented. In
the Runtime program the unit data is collected into an array. The first array position is the beginning of the
trial, and the last array position is the end of the trial. Each array position is referred to as a “bin” and
represents a period of time. For example, a bin could be defined as 4 msec in duration. Within each bin
is stored the number of units counted in that duration. In a typical trial, an array for the unit activity might
be made up of a succession of 250 bins; with each bin representing 4 msec, the whole trial is therefore
1000 msec (1 sec) in duration. Typically, a zero (0) is found in most bins, indicating that no unit activity
was found during that 4 msec period.
Cluster
The key to this analysis program is the definition of a cluster of unit activity. A “cluster” is defined
as a bin with unit activity or as a succession of bins that all have unit activity, bounded before and after by
bins with no unit activity. The following are a few examples of a cluster.
Example 1. Starting at the beginning of a trial we examine each bin. Initially, every bin has a
zero, indicating that no unit activity was recorded in that period. Then we encounter a bin with a count of
one, and the very next bin has a count of zero. The cluster is the bin with the unit activity, bounded by bins
before and after with no unit activity.
Example 2. Starting at the beginning of a trial we examine each bin. Initially, every bin has a
zero, indicating that no unit activity was recorded in that period. Then we encounter a bin with a count of
five, and the very next bin has a count of zero. The cluster is the bin with the unit activity, bounded by bins
before and after with no unit activity.
Example 3. Starting at the beginning of a trial we examine each bin. Initially, every bin has a
zero, indicating that no unit activity was recorded in that period. Then we encounter a bin with a count of
one, another bin with a count of one, a third bin with a count of two, and the very next bin has a count of
zero. The cluster is all the bins with the unit activity, bounded by bins before and after with no unit activity.
The number of units in this cluster is 4.
In each of the examples above, a cluster is defined as a group of neighboring bins which all have
unit activity. The actual source of that activity is not defined. The unit activity can be either single or
multiple unit data. The responsibility for the ultimate interpretation of the clusters depends upon the
experimenter.
Latency
The latency of the cluster is defined as the time when the first bin of the cluster is encountered.
The latency could be reported as the time since the beginning of the trial or as the time since some
meaningful event in the trial. For the latter we have chosen the time relative to the onset of the
conditioned stimulus (before or after CS onset).
Frequency
The frequency of the cluster is determined by the amount of unit activity in the cluster divided by
the time associated with the cluster, and scaled to activity per second (Hertz, Hz). The time associated
with the cluster has two components: the time of unit activity that makes up the cluster (the time
associated with the bins that have unit activity; see duration below) plus the time preceding the cluster
where no unit activity was recorded (see ici -- intercluster interval -- below). This formula works out to be
frequency in spikes/second
= ((1000 msec) * (#spikes_in_cluster)) / (duration_of_cluster msec + duration_of_ici msec)
The latter (the intercluster interval) will be recognized as a Poisson distribution. An easy way to
think about this distribution is to consider that random unit activity could be plotted as a function of the
interval between that same randomly generated activity. For example, pretend that unit activity has a
frequency of 10 Hz. If there was exact spacing between units, then one unit would occur every 100 msec.
That is the exact average. However, this exactness is very unlikely. Sometimes there could be a gap of
500 msec between units, sometimes a gap of only five msec. It could even be that all the unit activity
occurs close together, and that most of the time nothing happens. A plot of data that is randomly
distributed (that is, the intervals between unit activity is random) results in a plot where the sense is that if
you have waited a really long time and no unit activity has happened, then the chances are very good that
unit activity will happen before too long. Or another way of thinking about it: it would be surprising if unit
activity occurred too quickly or too infrequently. The point here is that the expectation about the frequency
of the units found in the cluster is a function of the preceding interval when nothing happened. Emissions
of radioactivity are another example of a Poisson distribution.
Other programs
The cluster analysis program, per se, was written after dissatisfaction with the performance,
limitations and assumptions that I have observed in other unit analysis programs. Crude comparisons of
unit activity with behavior can be made with cross-correlations. Arguments have been made that this is
the best way to determine whether the unit activity “models” the behavior; however, significant correlations
exist when the unit activity looks very different than the behavioral data (for example, when the unit activity
corresponds to the conditioned response, but the recording also includes tone evoked responses, which
do not correspond to the behavior). The “latency” of the unit is given as the lag of the cross-correlation
which yields the greatest correlation; yet the same analysis might yield several peaks and valleys of high
correlations (which one to use?) and the correlations are unlikely to be statistically distinguishable from
neighboring correlations. A statistically significant cross-correlation does not mean that there is a very
good match with the behavior or that the latency of unit activity is confidently determined. Further, as
practiced, the analysis is usually performed on data collected from several trials, rather than in individual
trials.
Another method is the use of z-scores. In one example of a z-score analysis, several trials are
combined and then the mean and standard error of the total unit activity in the baseline period are used to
compare the total unit activity in the CS period. An improvement is possible by using smaller time periods
that we refer to as “epochs” -- the first, middle and last thirds of the CS period, for example, could be
compared to a similar amount of time in the baseline period. The more epochs one has, the greater the
discrimination (within the limits of the length of the epoch) of when significant activity occurred. Also the
less stable the measurements because the baseline period similarly gets smaller. Typically, with three
epochs, we define epochs that we interpret to represent CS-related or CR-related activity. Latency
measurements of the unit activity are not reasonable expectations. This analysis is usually performed on
data collected from several trials, although once the baseline mean and standard error are determined
then epochs in individual trials can be compared for significant activity. To do this comparison, the actual
activity in the epoch for a trial is compared with the previously computed mean and standard error.
A different z-score method, again based on data from several trials, is designed to get at the
questions of how much activity is there, and when does the latency occur? The baseline period is used to
determine the mean and standard error for a bin (rather than for an epoch), and this is compared with
each bin in the CS period. To help this analysis a Gaussian curve of a few bins in duration is added to
each bin as a smoothing operation. The result is that bins that previously had no data now have some
Gaussian-added activity. As a result of this smoothing operation, the computed latency of unit activity
(when a bin exceeds a z-score criterion level) can occur in bins that actually had no activity. The size and
width of the Gaussian curve are massaged to prevent this -- in one early instance, for example, unit
activity was seen to occur before the airpuff was delivered. The assumptions inherent in this approach
lead me to suspect the arbitrariness of the latencies.
Another method is the use of t-scores. In this method, unit activity of the CS period is compared
with a similar period of baseline activity. The first bin of each period is compared, the second bin is next
compared, etc. The number of pairs of bins, for the whole CS period would be 63, which means that a zscore could be used instead. Typically, however, as with the epoch approach above, subsets (epochs) of
the CS period would be compared. As with the methods above, the analysis is usually performed on data
collected from several trials, and no reasonable latency score can be obtained.
Dissatisfaction
None of the above approaches analyzes unit data the way that we can do with our own eyes. We
can see, on a trial by trial basis, within each trial’s record, when unit activity appears to increase or to
decrease. What we are particularly bad at, however, is being able to determine when that activity began.
The purpose of the cluster analysis program is to approximate what our eyes do in such a way that the
program can reliably and consistently tell us when significant activity occurred.
The cluster program
The cluster analysis program is derived from a Windows version of the review program. The
review program should be familiar to the reader, and is written in MasterForth from Micromotion (now
defunct) for IBM DOS machines. The Windows version is written in WinForth from Laboratory
Microsystems. The review program allows one to see, on a trial by trial basis, or as an average of several
trials, the behavioral and unit data. The cluster program is based upon the cluster analysis portion of the
Windows review program with the added feature of printing out the results in a trial by trial format. Before
the Windows review program I had written a program to determine interspike intervals using MasterForth
from Micromotion for Apple II machines.
Rather than go into detail about how the cluster program works, the reader is probably more
interested in how to use the program and what the options are. The following is a description of the
cluster program and how to use it.
Loading the cluster program
On our 486 computer with Windows, open the Winforth group and double click on the Winforth
program to start it. You will see a notice that says that Winforth is ready and instructs you to press the OK
button or press <return> to continue. At this point you should see an “ok”, and every time you press
<return> you should see an “ok”. The “ok” tells you that you are talking to the forth interpreter.
To load the cluster program you first need to create a marker called “it”, you then need to load the
review program (called dave.txt) and then the cluster program (called cluster.txt).
create it<return>
include dave.txt<return>
include cluster.txt<return>
or
create it include dave.txt include cluster.txt<return>
Note that these can be on separate lines or all on the same line. The program will return with
some instructions and with an “ok”.
The instructions
You need to set several parameters before starting the program. Since this program is a work in
progress the instructions and their names may change in the future. The instructions may be something
like this:
Specify unit for analysis -- e.g., unit1, unit2 ...
Specify parameters -- e.g., bob, xty, claire_tones ...
Specify computations -- e.g., special_info, hz_info, latency_info, spike_info,
bin_info ...
Specify criterion level -- e.g., 3 equ unit_Hz_criterion
Specify bad trial criterion -- e.g., 100 equ bad_units
Specify type of analysis -- e.g., by_block or by_session
Set printer -- e.g., +printer, -printer, true equ printing, false equ printing
Start analysis with cluster<return>
Examples: unit2 bob hz_info 2 equ unit_Hz_criterion -printer cluster<return>
latency_info cluster<return>
unit1 +printer cluster<return> ...
You need to specify which unit you are analyzing, the training parameters, what kind of
information you want, what is your criterion for significant activity, what is your criterion for bad activity,
whether you want a block or session analysis, and whether you want a printout. You need to do this once
before actually running the program, and you can change any parameter at any time without having to respecify the other parameters. Let’s go through each of these:
Specify unit for analysis -- e.g., unit1, unit2 ...
Type unit1, unit2, unit3 or unit4 to analyze those unit channels, respectively. Those are the only legal
values.
Specify parameters -- e.g., bob, xty, claire_tones ...
Type bob or xty or claire_tones etc to automatically select the training parameters.
Or specify the individual parameters yourself for number of trials (108 equ #trls), number of trials
per block (9 equ #t/blk), number of blocks (12 equ #blks), the first trial to start with (1 equ trl#), the
number of a/d (eyelid data) that exists in this data (1 equ #a/d), the number of units in this data (4 equ
#units), the number of milliseconds (in whole numbers) per bin (4 equ bin), the total number of bins per
trial (756 bin / equ pts) [note that the forth commands here divide 756 msec by the 4 msec bin to yield the
number of bins that make up pts], the onset of the tone conditioned stimulus (252 bin / equ toneon), the
offset of the tone conditioned stimulus (598 bin / equ toneoff), the onset of the unconditioned stimulus
(504 bin / equ shkon), the offset of the unconditioned stimulus (598 bin / equ shkoff), and the horizontal
scaling used by the review program (3 equ xscalex). All of these parameters are loaded in when you type
bob. You could define your own set of parameters for your data.
Unknown to you, a trial type table is also assumed. This trial type table indicates the sequence of
tone alone (1), paired tone-airpuff (2) and air alone (3) trials. Currently it is set as
"122232222122232222122232222122232222122232222122232222122232222122232222122232222122
232222122232222122232222". To enter your own table, use a similar format and use:
"1222322221222322221222322221222322221222322221222322221222322221222322
22122232222122232222122232222122232222" trialtypetable strcpy
To make your own parameters and trial type table you would currently have to modify the file
dave.txt. DO NOT DO THIS. It is better for me to make a copy of the dave.txt file and rename it for you to
use.
Specify computations -- e.g., special_info, hz_info, latency_info, spike_info, bin_info ...
Type in your selection for the analysis. I think the most useful is special_info, which gives an x,y pair of
latency,hertz on the printout for every cluster found. The other options for cluster analysis are to print out
the frequency (hz_info), the latency (latency_info), unit count or spikes (spike_info), bin number
(bin_info), the intercluster interval (ici_info), cluster duration (duration_info). Hz_info prints a + in front
of significant high cluster activity, and prints a - in front of significant low cluster activity (see
unit_Hz_criterion next). Frequency for each cluster is calculated and reported to the 1s place, whereas
frequencies for the baseline and session are calculated and reported to the 0.01s place. Latency_info
prints a - in front of clusters that begin before CS onset. Latencies have the precision of the bin width -- if
the bin is 4 msec, then all reported latencies will be multiples of 4.
Specify criterion level -- e.g., 3 equ unit_Hz_criterion
You really do not have to specify this; you only have to specify this if you want to change it. The default is
currently 3 (3 equ unt_Hz_criterion). Alternatively, type any whole number using this format to define the
frequency criterion. This parameter is used to determine significant unit activity. The frequency of each
cluster is compared with some baseline activity times (for high activity) or divided by (for low activity) the
unit_Hz_criterion. The baseline activity is the preCS activity for the block (see by_block below) or for the
session (see by_session below). In addition, preCS activity reported for each block is always compared
with the preCS activity of the session, and indicated with a + or - sign if it is significant.
This method for determining significance is so simple that it seems too good to be true. But it is
true. Because of the number of observations involved, calculation of the mean and standard error of
preCS frequencies yields a very small standard error. Even using several standard errors to determine
significance is less conservative than simply using two or three times the baseline frequency.
For the test file that I have been using to write this program (file = data.bob) the baseline is 14.14
+/- 2.28 Hz (mean +/- standard error). In this instance, using a criterion of twice the frequency is more
than 6 times the standard error.
Obviously, the standard error would be much greater when calculating the baseline frequency of a
block of trials (because a block has fewer trials than the whole session). For the first block of the the
data.bob file, the mean and standard error is 49.03 +/- 6.66 Hz when just using the data in the print out.
The point here is that the standard error of 6.66 for the block is about 3 times the error for the day.
Also noticed is that the mean reported for the first block (14.12 Hz) is not the same as what was
just calculated (49.03) and that the frequencies reported at the end of the trials for the preCS activity does
not have an obvious relation to either number (for trials 1-9 the frequencies are 12.71, cannot calculate,
25.42, 25.42, 41.67, 46.88, cannot calculate, 62.50, and 30.00). The discrepancy is due to the way that
individual trials (i) cannot calculate the very first frequency, (ii) do not consider inactivity in the previous
trial, and as a result (iii) cannot take into consideration frequencies when less than two clusters occur in
the trial’s preCS period.
A comparison of the frequencies for the individual trials with the frequency reported for the second
block of data.bob (where there are not trials with “cannot calculate”) yields 18.66 versus 17.79
(respectively), which is much closer. This still does not take into consideration the very first cluster of
every trial (i.e., clusters that begin at the end of one trial and start at the beginning of the following trial, as
assumed by the baseline calculations). Based on the clusters reported in the printout for the second
block, the mean +/- standard error are 40.68 +/- 6.34, which again does not take into consideration the the
very first cluster or the clusters that span over trials.
A simple calculation of the session preCS frequency found by dividing the total number of preCS
units (385) by the total preCS time (252 msec times 107 good trials) and scaling for 1 second yields 14.28
Hz. This is very close to the reported session preCS frequency of 14.14 Hz. The reason they are not
exactly the same is because the reported session preCS frequency does not include the time before the
very first cluster of the session, does not include the units in the very first cluster of the session, and does
not include the time after the very last cluster of the session -- all of which seem very reasonable to me.
The reported frequency of 14.14 Hz is what I believe.
The bottom line is that the trial, block and session frequencies and the trial clusters are accurately
being reported on the printout. See assumptions below.
[If you do analyze data.bob you might notice that trials 3 and 4 yield the same print outs -- that is
because I copied trial 3 over trial 4 (or vice versa) because previously I had purposely corrupted the
baseline of trial 4 (or trial 3) to create a bad trial when I was testing the programs.]
Specify bad trial criterion -- e.g., 100 equ bad_units
You really do not have to specify this; you only have to specify this if you want to change it. The default is
currently 50 (50 equ bad_units). What this means is that if the total amount of unit activity found in the
preCS period exceeds 50 counts, then that trial is treated as a bad trial and it is not included in the
calculations.
Specify type of analysis -- e.g., by_block or by_session
You really do not have to specify this; you only have to specify this if you want to change it. The default is
currently by_blocks. This parameter is used for determining whether the clusters in a trial will be
compared with the preCS frequency that was computed for the block that the trial resides in (by_block),
or compared with the preCS frequency that was computed for the entire session (by_session).
Set printer -- e.g., +printer, -printer, true equ printing, false equ printing
You really do not have to specify this; you only have to specify this if you want to change it. The default is
currently set so that the analysis is displayed on the monitor, not the printer (-printer, which is the same
as false equ printing).
Start analysis with cluster<return>
You start the analysis by typing cluster<return> . This command used to be xxx but it was recently
changed -- I use xxx as a handy abbreviation when I am writing and debugging programs. That way, I do
not have to remember what is the execute command (eXecute, xxx -- get it?).
Once you start the analysis, you will be asked for the name of the file to analyze. You can specify
the file name and the drive in the popup window.
As the analysis proceeds to display (on the monitor) or print (on the laser printer) trial by trial,
(almost) any press of any key will temporarily halt the display or printout. (Almost) any other key press will
cause the display to continue. It is probably a good idea to keep your hands off the keyboard when
printing -- you might accidentally pause the printing operation and not realize it, and end up wondering
what is going on. The one special key is the <return> key -- pressing <return><return> or pressing any
(other) key and then pressing <return> as the second key will cause the analysis to abort.
Note that in the examples given they show that the commands can be given all on one line, and
that multiple analyses can be done.
The printout
The printout tells you the file that the analysis is for, the type of data that is being reported, the unit
criterion, the bad trial criterion, whether the analysis is by block or by session, and the number of unit
channel being analyzed.
The data is printed out trial by trial, and organized into blocks. Each trial is described as T (tone
alone), P (paired) or A (air alone), followed by the trial number. If the trial is bad (i.e., if too many preCS
unit counts were made) then this is indicated and no further computations are made for that trial. If the
trial is good, then the clusters are printed out according to the type of information that you requested.
PreCS clusters are separated from CS clusters by a “/” mark; CS clusters separated from UCS clusters by
“//” marks. A new line is forced on the laser printer or the record would go beyond the right side of the
page -- this sometimes leaves + or - signs or pairs of numbers on another line. [This is not a bug, it is just
some prettying that I have not got around to fixing up.] At the end of the line is printed the preCS
frequency for that trial (computed to 0.01 places) unless there are fewer than two clusters in the preCS
period of that trial and then the message “cannot calculate PCS Hz” appears.
The reason for this message is that the frequency of the very first cluster cannot be computed
because it cannot be determined what the preceding intercluster interval should be. In working out
different computation schemes I found that strangely high frequencies would be reported if I made the
assumption that the intercluster interval began at the start of the trial. For example, if a unit occurred near
the very beginning then the frequency of its cluster would be computed to be very high, even though the
remaining clusters in the preCS period could be very low. I decided that it was better to drop the
calculations for the first cluster rather than making an assumption about when previous activity might or
might not have occurred. (See assumptions below.)
At the end of every block the block number and the block’s preCS frequency is printed. The block
frequency (to 0.01 places) is always compared with the preCS frequency computed for the entire session.
A + is placed before the block’s preCS frequency if it is significantly above the session preCS frequency,
and a - is placed if the block’s preCS frequency is significantly below the session preCS frequency. This is
useful to know because it tells whether the preCS activity changes from block to block over the course of
the session.
Finally, at the end of the print out, is reported the total number of preCS units, the number of good
trials, and the preCS frequency for the whole session (to 0.01 places).
Creating a disk file
If you wish to save the print out to a disk file instead of printing on the laser printer or to the
console then you can use the following:
>file c:\winforth\results.txt cluster console <return>
or, if you are already in the directory that you wish, simply use
>file results.txt cluster console <return>
or, better yet, save to a floppy disk with
>file b:results.txt cluster console <return>
It is important to type this all on one line, with appropriate spacing and no errors, and to make sure that
the filename does not already exist (here results.txt, but any legal DOS name can be used) -- if it already
exists then that data will be written over.
It would be a better idea if you save this on a floppy disk. A printout-to-disk using special_info
yielded a file more than 21k in size. A lot of files like this would easily take up all the hard disk space. So I
recommend that you save to a floppy instead of to the hard drive.
Removing a disk file
If you wish to remove the file you just created above then you can type
del results.txt <return>
That’s all there is to it. Be sure that you are removing the file that you intend.
Assumptions
Very few assumptions are actually made in this analysis.
First, I am assuming that clustering is a reasonable thing to do -- that seems to be what my eye
and brain is doing when I look at unit activity. For single unit activity the only real question is whether the
precision of the data -- determined by the bin width -- can resolve frequencies and latencies. Given the
nature of the data, and experience with the analysis, I think this is reasonable within those limits. Whether
single and multiple unit activity can be treated in the same way is an open question. If multiple unit data is
considered to be a sample of single units then I see no problem as long as one’s conclusions stay within
the limits of the data -- (i) that this is a sample, (ii) that conclusions about individual units cannot be made.
Second, since I am not using the standard error of preCS activity, I am not making any
assumptions about a normal distribution. But I am assuming that a simple arithmetic computation (two or
three times the baseline activity, for example) is a reasonable way to determine significant unit activity.
This seems reasonable to me since (i) this is far more conservative than using standard errors, and (ii) it
is far easier to compute.
Third, the only other assumption that I recall occurs in the computation of the preCS baseline.
The frequency of the very first cluster of every trial is not computed when printing out each trial’s clusters
because the previous period of inactivity is indeterminate. When computing the session preCS baseline,
however, if I adopted this strategy of dropping the first cluster of every trial, then I would lose a lot of
clusters in the course of a session (in a session of 108 trials, I could potentially lose 108 clusters).
Instead, for the computation of preCS baseline for both the block and session (but not for reporting
clusters for every trial), I pretend that all the preCS baseline periods occur one right after the other. That
way, for example, the intercluster interval on the second trial includes the period of inactivity at the
beginning of its baseline period and it includes the inactivity at the end of the preceding trial, trial 1.
Therefore, for computing the baseline frequency, only the very first cluster of the block or of the session is
excluded in the computation of the frequency. It seems to me that this is a reasonable assumption if the
baseline preCS periods are truly independent of each other and representative samples, and because this
approach includes as much of the data as possible. This is confirmed by the fact that the reported
frequency for the session for the file data.bob of 14.14 Hz is very close to the frequency when the total
number of units is divided by the total amount of baseline time (14.28 Hz).
Cluster analysis source code: dave.txt
The following is the actual source code for the basic implementation of the cluster program. This
file, dave.txt, is a modification of the Review routine that has been imported from the Summary program.
As noted above, this program differs from other Forth programs we have seen in that it does not use the
'screen' structure of the original Forth programming, comments are mostly enclosed in parentheses, and
some of the programming is specific to implementing and maintaining windows (Windows 3.1). Note that
we have made good use of the case structure that is available for this version of Forth for programming
options.
(
(
(
(
(
(
(
(
(
(
(
o based on demo27.4th using GDI drawing Copyright C 1993 LMI)
o created as dave.4th on 04jan96dgl)
o functions with the printer. )
o however, i just spent a long time with C and windows and did not)
o figure out how to use the printer correctly. gave up. 12mar96dgl.)
o most recent update of dave.4th was 23may96dgl)
o created as dave.txt on 11 February 1997 -- brought 4th files together into one large txt file)
o dave.txt modified 12 Februarry 1997 -- prettying format)
o dave.txt modified 11 March 1997 -- prettying format)
o dave.txt modified 12 March 1997 -- rename some words)
o dave.txt modified 25 March 1997 -- added +printer, -printer, frequency_info, freq_info)
forget it
create it
( programming helps ...)
1024 constant 1k
13 constant eol#
27 constant esc#
0 constant dummy
80 equ items
0 equ counter ( used by graphics.)
0 equ _trl# ( temporary storage for trial number; used by graphics.)
: nuf? ( -- flag)
false
?terminal ( was there a key press?)
if
key drop ( don't care what first key was)
key eol# = ( is second key a return?)
if
drop true
then
then ;
: u<= ( n1 n2 -- flag) 2dup = -rot u< or ;
( printer enhancements)
false equ printing
: page ( --) 12 emit ;
: +condensed ( --) esc# emit " (s16.66h8.5v0T" count type ;
: -condensed ( --) esc# emit " (s12h10v3T" count type ;
: +printer ( --) true equ printing ;
: -printer ( --) false equ printing ;
( the following was originally in the file definitions.run)
( common definitions for runtime/summary programs)
( runtime/summary definitions)
( total)
( counter)
0 equ #a/d
0 equ a/d#
0 equ #units
0 equ unit#
0 equ #trls
0 equ #blks
0 equ #t/blk
0 equ trl#
0 equ blk#
0 equ t/blk#
0 equ bin
0 equ pts
0 equ toneon
0 equ lton
0 equ shkon
0 equ bin#
0 equ toneoff
0 equ ltoff
0 equ shkoff
6 equ badtime ( Note: this is in bins, not milliseconds)
7 equ bada/d
0 equ badtrial ( flag for bad trial)
50 equ bad_units ( number of counts in entire preCS period)
( bad_units is used in .info, .cmds, get_PCS_spikes, bad_PCS_spikes)
40 equ baseln ( Note: this is in bins, not milliseconds, before CS period)
5 equ critlevel ( CS period criterion level for a/d)
3 equ unit_Hz_criterion
( used for graphing Hz for several trials.)
1 equ start
10 equ end
0 equ stagger
1 equ _unit# ( temporary storage variable)
: valid_trials ( to fr -- to|to' fr|fr') 1 max swap #trls 1+ min swap ;
: through ( start end --) valid_trials equ end equ start ;
ascii 0 equ tones
ascii 0 equ airs
ascii 0 equ pairs
: tone ( --) ascii 1 equ tones ascii 0 equ pairs ascii 0 equ airs ;
: paired ( --) ascii 0 equ tones ascii 2 equ pairs ascii 0 equ airs ;
: air ( --) ascii 0 equ tones ascii 0 equ pairs ascii 3 equ airs ;
: all ( --) ascii 1 equ tones ascii 2 equ pairs ascii 3 equ airs ;
: trial ( --) noop ;
: trials ( --) noop ;
: alone ( --) noop ;
all trials ( default)
( used for graphing single trial display.)
0 equ mode ( 0 = unit histogram, 1 = unit frequency )
( common values ...)
0 equ array ( used to hold pointer to beginning of data bloc)
3 equ xscalex
1 equ a/d1x 1 equ a/d2x 1 equ a/d3x 1 equ a/d4x
3 equ a/d1/ 3 equ a/d2/ 3 equ a/d3/ 3 equ a/d4/
3 equ unit1x 3 equ unit2x 3 equ unit3x 3 equ unit4x
1 equ unit1/ 1 equ unit2/ 1 equ unit3/ 1 equ unit4/
1 equ hz1x
3 equ hz1/
( drawing variables ...)
0 equ offset ( used to set y origin of plot)
0 equ cr_offset ( used by calculating functions)
0 equ x1
0 equ y1
0 equ x2
0 equ y2
( switches ...)
0 equ trial/-block ( 0 = trial, 1 = block, 2 = unit frequencies)
false equ bad_trial?
false equ info ( display info about CR criteria, etc.)
false equ cmds
( measurements ...)
0 equ PCSamp+ 0 equ PCSamp- 0 equ PCSpklat+ 0 equ PCSpklat- 0 equ |PCSamp|
0 equ baseline
0 equ CSamp+ 0 equ CSamp- 0 equ CSpklat+ 0 equ CSpklat- 0 equ CScrit+
0 equ CScrit0 equ UCSamp+ 0 equ UCSamp- 0 equ UCSpklat+ 0 equ UCSpklat- 0 equ UCScrit+
0 equ UCScrit0 equ accumulator
( arrays ...)
create ram1 1024 allot ram1 1024 erase
create ram2 2048 allot ram2 1024 erase
create string1 256 allot
create string2 256 allot
( the following used to be in the file trialtypes.run )
( trial type table )
create trialtypetable 512 allot trialtypetable 512 erase
( data.ben ...)
("
122223222212222322221222232222122223222212222322221222232222122223222212222322221222
2322221222232222" trialtypetable strcpy)
( data.bob, claire_tones, claire_lights ...)
"
122232222122232222122232222122232222122232222122232222122232222122232222122232222122
232222122232222122232222" trialtypetable strcpy
( the following used to be in the file datasets.run )
( bob, xty, ben)
: bob ( --) ( parameters for data.bob ...)
1 equ trl# 9 equ #t/blk 108 equ #trls 12 equ #blks
1 equ #a/d
4 equ #units
4 equ bin
756 bin / equ pts 252 bin / equ toneon 598 bin / equ toneoff 504 bin / equ shkon
598 bin / equ shkoff 3 equ xscalex ;
: xty ( --) ( parameters for data.xty ...)
1 equ trl# 9 equ #t/blk 108 equ #trls 12 equ #blks
1 equ #a/d
4 equ #units
4 equ bin
756 bin / equ pts 252 bin / equ toneon 598 bin / equ toneoff 504 bin / equ shkon
598 bin / equ shkoff 3 equ xscalex ;
: ben ( --) ( parameters for data.ben ...)
1 equ trl# 10 equ #t/blk 100 equ #trls 10 equ #blks
4 equ #a/d
0 equ #units
4 equ bin
1000 bin / equ pts 248 bin / equ toneon 596 bin / equ toneoff 496 bin / equ shkon
596 bin / equ shkoff 2 equ xscalex ;
: claire_tones ( --) ( parameters for claire with tones)
1 equ trl# 9 equ #t/blk 108 equ #trls 12 equ #blks
1 equ #a/d
4 equ #units
4 equ bin
756 bin / equ pts 252 bin / equ toneon 598 bin / equ toneoff 504 bin / equ shkon
598 bin / equ shkoff 3 equ xscalex ;
: claire_lights ( --) ( parameters for claire with lights)
1 equ trl# 9 equ #t/blk 108 equ #trls 12 equ #blks
1 equ #a/d
4 equ #units
4 equ bin
1008 bin / equ pts 252 bin / equ toneon 856 bin / equ toneoff 756 bin / equ shkon
856 bin / equ shkoff 3 equ xscalex ;
( the following used to be in the file windows.run )
( local variables for drawing & printing )
0 equ xpixels/inch ( logpixelsx)
0 equ localpagex
0 equ localhorizmarg
0 equ localdc
0 equ localfrom
2variable 2upperleft
0 equ rightside
0 equ ypixels/inch ( logpixelsy)
0 equ localpagey
0 equ localvertmarg
0 equ localto
2variable 2lowerright
0 equ bottomside
( magic numbers from WINDOWS.H from DEVCAPS.4TH ...)
( mapping modes ...)
1 constant mm_text ( pixel)
2 constant mm_lometric ( 0.1 mm)
3 constant mm_himetric ( 0.01 mm)
4 constant mm_loenglish ( 0.01 inch)
5 constant mm_hienglish ( 0.001 inch)
6 constant mm_twips ( 1/1440 inch)
7 constant mm_isotropic ( arbitrary x=y)
8 constant mm_anisotropic ( arbitrary x<>y)
( 0 CONSTANT DRIVERVERSION )
( 2 CONSTANT TECHNOLOGY )
4 CONSTANT HORZSIZE ( width in mm )
6 CONSTANT VERTSIZE ( height in mm )
8 CONSTANT HORZRES ( width in pixels )
10 CONSTANT VERTRES ( height in pixels )
12 CONSTANT BITSPIXEL
(
(
(
(
(
(
(
(
(
(
(
(
(
14 CONSTANT
16 CONSTANT
18 CONSTANT
20 CONSTANT
22 CONSTANT
24 CONSTANT
26 CONSTANT
28 CONSTANT
30 CONSTANT
32 CONSTANT
34 CONSTANT
36 CONSTANT
38 CONSTANT
40 CONSTANT
42 CONSTANT
44 CONSTANT
88 CONSTANT
90 CONSTANT
( 104 CONSTANT
( 106 CONSTANT
( 108 CONSTANT
WCB MAINWIN
PLANES )
NUMBRUSHES)
NUMPENS )
NUMMARKERS )
NUMFONTS )
NUMCOLORS )
PDEVICESIZE )
CURVECAPS )
LINECAPS )
POLYGONALCAPS )
TEXTCAPS )
CLIPCAPS )
RASTERCAPS )
ASPECTX ( relative width in pixels )
ASPECTY ( relative height in pixels )
ASPECTXY ( relative diagonal in pixels)
LOGPIXELSX ( width in pixels per inch )
LOGPIXELSY ( width in pixels per inch )
SIZEPALETTE )
NUMRESERVED )
COLORRES )
( window control block for frame window)
( the following used to be in the file popups.run )
create filename 64 allot filename 64 erase
: selectfile ( --) ( open data file for analysis ...)
( NOTE: open-scr automatically closes previous block file before opening new one.)
" Data files | data.* | Block files | *.scr | All files | *.*" opendlg
dup filename strcpy
open-scr
if ." Invalid file selection" quit then ;
( arbitrary identifiers for menu items)
100 CONSTANT IDM_FILEPRINT
101 CONSTANT IDM_FILEEXIT
102 CONSTANT idm_openfile
103 constant idm_trial+
104 constant idm_trial105 constant idm_jump
106 constant idm_block+
107 constant idm_block108 constant idm_stop
109 constant idm_start
110 constant idm_end
111 constant idm_interpretter
112 constant idm_source
( 113 constant idm_average)
114 constant idm_info
115 constant idm_cmds
MENU APPMENU
" &File" POPUP
" &Open" idm_openfile mf_enabled menuitem
" &Print" IDM_FILEPRINT MF_ENABLED MENUITEM
""
0
MF_SEPARATOR MENUITEM
" &Exit" IDM_FILEEXIT MF_ENABLED MENUITEM
END-POPUP
" |<"
idm_start
mf_enabled menuitem
" <<"
idm_blockmf_enabled menuitem
" <"
idm_trialmf_enabled menuitem
( " -"
idm_stop
mf_enabled menuitem)
" >"
idm_trial+
mf_enabled menuitem
" >>"
idm_block+
mf_enabled menuitem
" >|"
idm_end
mf_enabled menuitem
" &Jump"
idm_jump
mf_enabled menuitem
" &Interpretter" idm_interpretter mf_enabled menuitem
" &Source"
idm_source
mf_enabled menuitem
( " &Average"
idm_average
mf_enabled menuitem)
" i&Nfo"
idm_info
mf_enabled menuitem
" &Cmds"
idm_cmds
mf_enabled menuitem
END-MENU
100 equ id_ok
102 equ id_input
103 equ id_cancel
104 equ id_interpretter
" Jump to Trial #..." 100 20 110 50 DS_MODALFRAME WS_CAPTION D+ WS_POPUP D+
dialog jumpdlg
" Enter Trial Number" 10 10 70 16 -1
ltext
80 10 20 12 id_input edittext
" OK"
24 30 32 16 id_ok
defpushbutton
" Cancel"
64 30 32 16 id_cancel pushbutton
END-DIALOG
variable jump# 1 jump# !
: jumpprocedure ( -- flag) ( this is the callback handler for jump)
wMsg WM_INITDIALOG =
if id_input jump# @ dsetuint true exit then
wMsg WM_COMMAND =
if wParam id_ok =
if
id_input dgetuint jump# !
1 closedlg
else
wParam id_cancel =
if 0 closedlg then
then
then
false ;
" Interpretter ..." 50 20 200 60 DS_MODALFRAME WS_CAPTION D+ WS_POPUP D+
dialog interpretterdlg
" Enter Forth Command" 10 5 70 16 -1
ltext
10 15 180 12 id_input edittext
" OK"
70 35 30 16 id_ok
defpushbutton
" Cancel"
110 35 30 16 id_cancel pushbutton
END-DIALOG
create interpretterbuffer 80 allot interpretterbuffer 80 erase
: interpretterprocedure ( -- flag) ( this is the callback handler for jump)
wMsg WM_INITDIALOG =
if id_input interpretterbuffer dsettext true exit then
wMsg WM_COMMAND =
if wParam id_ok =
if
id_input dgettext interpretterbuffer strcpy
1 closedlg
else
wParam id_cancel =
if 0 closedlg then
then
then
false ;
( " Average Trials ..." 100 20 90 50 DS_MODALFRAME WS_CAPTION D+ WS_POPUP D+)
( dialog averagedlg)
( " Enter Beginning Trial Number" 5 10 70 16 -1
ltext)
(
75 10 10 12 id_input edittext)
( " OK"
5 30 32 16 id_ok
defpushbutton)
( " Cancel"
40 30 32 16 id_cancel pushbutton)
( END-DIALOG)
( variable averagestart 1 averagestart !)
( : averageprocedure (( -- flag \\ this is the callback handler for jump)
( wMsg WM_INITDIALOG =)
( if id_input averagestart @ dsetuint true exit then)
( wMsg WM_COMMAND =)
( if wParam id_ok = )
( if)
(
id_input dgetuint averagestart ! )
(
1 closedlg)
( else )
(
wParam id_cancel =)
(
if 0 closedlg then)
( then)
( then )
( false ;)
: legendfont ( --)
" Arial" ( ^fontname) ff_swiss ( family) 10 ( size) fs_normal fs_bold or ( style) localdc ( wcb)
wsetfont ;
: coloring ( dn --) 2dup ( dn dn) pen ( dn) brush ;
( the following used to be in the file measure1.run )
( printout text output)
( : .out$ \\ str --)
( >r localdc dup GetCurrentPosition ds0 r> \\ str\\ count TextOut drop ;)
( : .out# \\ # --)
( >r localdc dup GetCurrentPosition ds0 r> \\ #\\ s>d <# #s #> TextOut drop ;)
( : .out.# \\ # --)
( >r localdc dup GetCurrentPosition ds0 r> \\ #\\ s>d <# # ascii . hold #s #> TextOut drop ;)
( : .out#$ \\ i+1|trl# str --)
( swap >r >r localdc dup GetCurrentPosition ds0 r> \\ str\\ count r> \\ i+1\\ s>d <# #s #> strcat TextOut
drop ; )
: mm>string ( n -- adr #) s>d <# bl hold #s #> ;
: mm>+-string.r ( n -- adr #) ( 10ths decimal place AND takes into account sign.)
s>d dup -rot dabs <# bl hold # ascii . hold #s rot sign #> ;
: ms>string ( n -- adr #) s>d <# bl hold #s #> ;
: ms>+-string ( n -- adr #) s>d dup -rot dabs <# bl hold #s rot sign #> ;
: device_cr ( --) ( device-independent carriage return)
localdc 0 ( x) offset ( y) SetViewportOrg 2drop
localdc 0 0 Moveto 2drop
offset printing if 40 else 20 then + equ offset ;
: .trial# ( --) ( print trial #)
legendfont
lightred coloring
device_cr
localdc dup GetCurrentPosition ds0
trial/-block
case
0 of ( trial ...)
" trial # " string1 strcpy
string1 count trl# mm>string strcat
" calculations ... " count strcat
endof
1 of ( block ...)
" block average" string1 strcpy string1 count
" , trials " count strcat
start mm>string strcat
" through " count strcat
end mm>string strcat
" ; trial types = " count strcat
tones ascii 1 =
pairs ascii 2 = and
airs ascii 3 = and
if
" all " count strcat
else
tones ascii 1 = if " tones " count strcat then
pairs ascii 2 = if " paired " count strcat then
airs ascii 3 = if " airs " count strcat then
then
endof
2 of ( unit frequencies ...)
" unit # " string1 strcpy string1 count
unit# mm>string strcat
" , trials " count strcat
start mm>string strcat
" through " count strcat
end mm>string strcat
" ; trial types = " count strcat
tones ascii 1 =
pairs ascii 2 = and
airs ascii 3 = and
if
" all " count strcat
else
tones ascii 1 = if " tones " count strcat then
pairs ascii 2 = if " paired " count strcat then
airs ascii 3 = if " airs " count strcat then
then
endof
endcase
TextOut drop
device_cr
noop ;
: .info ( --) ( print information)
info
if
localdc dup GetCurrentPosition ds0
"
a CR is movement >= " string1 strcpy
string1 count critlevel mm>+-string.r strcat
" mm between tone onset plus " count strcat
badtime bin * ms>string strcat
" ms" count strcat
TextOut drop
device_cr
localdc dup GetCurrentPosition ds0
"
and airpuff onset" count
TextOut drop
device_cr
localdc dup GetCurrentPosition ds0
"
a bad trial is movement >= +/-" string1 strcpy
string1 count bada/d mm>+-string.r strcat
" mm in the " count strcat
baseln bin * ms>string strcat
" ms before CS onset" count strcat
TextOut drop
device_cr
localdc dup GetCurrentPosition ds0
"
or >= +" string1 strcpy
string1 count bada/d mm>+-string.r strcat
" mm between CS onset and CS onset plus " count strcat
badtime bin * ms>string strcat
" ms" count strcat
TextOut drop
legendfont
lightred coloring
device_cr
localdc dup GetCurrentPosition ds0
"
also, a CR is unit activity > " string1 strcpy
string1 count unit_Hz_criterion mm>string strcat
" times each unit's PCS baseline frequency " count strcat
TextOut drop
device_cr
localdc dup GetCurrentPosition ds0
"
and, a bad trial is unit actvity >= " string1 strcpy
string1 count bad_units mm>string strcat
" counts in the entire PCS period" count strcat
TextOut drop
device_cr
then ;
: .cmds ( --) ( print commands)
cmds
if
device_cr
trial/-block
case
0 of ( trial)
localdc dup GetCurrentPosition ds0
" The following commands are available for trial analysis:" string1 strcpy string1 count TextOut drop
device_cr
localdc dup GetCurrentPosition ds0
"
frequency, frequencies, histogram, histograms, n equ unit_Hz_criterion," string1 strcpy string1
count TextOut drop device_cr
localdc dup GetCurrentPosition ds0
"
ici_info, duration_info, spike_info, time_info, bin_info (raw_info)," string1 strcpy string1 count
TextOut drop device_cr
localdc dup GetCurrentPosition ds0
"
latency_info, hz_info, n equ bada/d, n equ badtime [postCS], n equ baseln [preCS], and n equ
bad_units." string1 strcpy string1 count TextOut drop device_cr
localdc dup GetCurrentPosition ds0
"
Execution is transparent to user (no special command) for trials." string1 strcpy string1 count
TextOut drop device_cr
endof
1 of ( block)
localdc dup GetCurrentPosition ds0
" The following commands are available for block analysis:" string1 strcpy string1 count TextOut drop
device_cr
localdc dup GetCurrentPosition ds0
"
zero, n1 n2 through, add, subtract, average," string1 strcpy string1 count TextOut drop device_cr
localdc dup GetCurrentPosition ds0
"
tone, tone alone, air, air alone, alone, paired, all trials, all, trials." string1 strcpy string1 count
TextOut drop device_cr
localdc dup GetCurrentPosition ds0
"
n equ bada/d, n equ badtime [postCS], n equ baseln [preCS], and n equ bad_units." string1
strcpy string1 count TextOut drop device_cr
localdc dup GetCurrentPosition ds0
"
Execution is through add, subtract and average." string1 strcpy string1 count TextOut drop
device_cr
localdc dup GetCurrentPosition ds0
"
E.g.: zero paired 1 10 through add average." string1 strcpy string1 count TextOut drop device_cr
endof
2 of ( frequencies)
localdc dup GetCurrentPosition ds0
" The following commands are available for frequency analysis:" string1 strcpy string1 count TextOut
drop device_cr
localdc dup GetCurrentPosition ds0
"
n1 equ start, n2 equ end, n1 n2 through, unit1, unit2, unit3, unit4," string1 strcpy string1 count
TextOut drop device_cr
localdc dup GetCurrentPosition ds0
"
n1 equ unit_Hz_criterion, and n equ stagger; tone alone, air alone, paired, all trials, " string1
strcpy string1 count TextOut drop device_cr
localdc dup GetCurrentPosition ds0
"
n equ bada/d, n equ badtime [postCS], n equ baseln [preCS], and n equ bad_units." string1
strcpy string1 count TextOut drop device_cr
localdc dup GetCurrentPosition ds0
"
Execution is transparent to user (no special command) for frequencies." string1 strcpy string1
count TextOut drop device_cr
localdc dup GetCurrentPosition ds0
"
E.g.: unit2 paired 1 10 through." string1 strcpy string1 count TextOut drop device_cr
endof
endcase
localdc dup GetCurrentPosition ds0
" Where n, n1 and n2 are numbers the user enters on the stack." string1 strcpy string1 count TextOut
drop device_cr
then ;
: print_a/d_data ( --) ( print data legend)
legendfont
lightred coloring
device_cr
localdc dup GetCurrentPosition ds0
" a/d # " string1 strcpy
string1 count ( adr1 #1) a/d# s>d <# #s #> ( adr1 #1 adr2 #2) strcat
" ... " count strcat
"
" count strcat ( this adds spaces before the numbers)
baseline mm>string strcat
"
" count strcat
PCSamp+ mm>+-string.r strcat
PCSpklat+ ms>string strcat
PCSamp- mm>+-string.r strcat
PCSpklat- ms>string strcat
|PCSamp| mm>+-string.r strcat
"
" count strcat
CSamp+ mm>+-string.r strcat
CSpklat+ ms>string strcat
CScrit+ ms>+-string strcat
CSamp- mm>+-string.r strcat
CSpklat- ms>string strcat
CScrit- ms>+-string strcat
"
" count strcat
UCSamp+ mm>+-string.r strcat
UCSpklat+ ms>string strcat
UCScrit+ ms>+-string strcat
UCSamp- mm>+-string.r strcat
UCSpklat- ms>string strcat
UCScrit- ms>+-string strcat
"
" count strcat
badtrial ms>+-string strcat
( calculate badtrial = badtime + bada/d ...)
bada/d |PCSamp| u<=
badtrial
0= or
badtrial
0> or
if "
bad" count strcat then
( calculate CR trial = valid CRcrit+ ...)
trl# 1- trialtypetable 1+ + c@ ascii 1 = ( tone alone trials)
if
CScrit+
0=
CScrit+
0> or
UCScrit+
0= or
UCScrit+
0> or
if " CR" count strcat then
then
trl# 1- trialtypetable 1+ + c@ ascii 2 = ( tone-airpuff trials)
if
CScrit+
0=
CScrit+
0> or
if " CR" count strcat then
then
TextOut drop ;
( the following used to be in the file measure2.run )
( a/d analysis)
: measure_baseline ( --)
000 ( dummy) toneon ( to) 0 ( fr)
?do array i + c@ + loop toneon / equ baseline ;
: measure_badtime ( --)
toneon badtime + bin * negate equ badtrial ( default_value)
toneon badtime + ( to) toneon ( fr)
?do array i + c@ baseline bada/d - u<=
if i toneon - bin * equ badtrial leave then loop ( actual crit latency) ;
: measure_a/ds_precs ( --)
000 ( dummy) toneon ( to) toneon baseln - 0 max ( fr)
?do array i + c@ max loop ( fake minimum_value | dummy) equ PCSamptoneon ( to) toneon baseln - 0 max ( fr)
?do array i + c@ PCSamp- = if i leave then loop ( actual minimum latency) equ PCSpklat255 ( dummy) toneon ( to) toneon baseln - 0 max ( fr)
?do array i + c@ min loop ( fake maximum_value | dummy) equ PCSamp+
toneon ( to) toneon baseln - 0 max ( fr)
?do array i + c@ PCSamp+ = if i leave then loop ( actual maximum latency) equ PCSpklat+
( corrections: invert calculations for actual values ...)
baseline PCSamp+ - equ PCSamp+
baseline PCSamp- - equ PCSampPCSamp+ PCSamp- - abs equ |PCSamp|
PCSpklat+ bin * equ PCSpklat+
PCSpklat- bin * equ PCSpklat- ;
: measure_a/ds_cs ( --)
000 ( dummy) shkon ( to) toneon ( fr)
?do array i + c@ max loop ( fake minimum_value | dummy) equ CSamp000 ( dummy) shkon ( to) toneon ( fr)
?do array i + c@ CSamp- = if i + leave then loop ( actual minimum latency) equ CSpklat255 ( dummy) shkon ( to) toneon ( fr)
?do array i + c@ min loop ( fake maximum_value | dummy) equ CSamp+
000 ( dummy) shkon ( to) toneon ( fr)
?do array i + c@ CSamp+ = if i + leave then loop ( actual maximum latency) equ CSpklat+
( calculate CS +criterion ...)
shkon toneon - bin * negate equ CScrit+ ( default_value)
shkon ( to) toneon badtime + ( fr)
?do array i + c@ baseline critlevel - u<=
if i toneon - bin * equ CScrit+ leave then loop ( actual crit latency)
( calculate CS -criterion ...)
shkon toneon - bin * negate equ CScrit- ( default_value)
shkon ( to) toneon badtime + ( fr)
?do array i + c@ baseline critlevel + swap u<=
if i toneon - bin * equ CScrit- leave then loop ( actual crit latency)
( corrections: invert calculations for actual values ...)
baseline CSamp+ - equ CSamp+
baseline CSamp- - equ CSampCSpklat+ toneon - bin * equ CSpklat+
CSpklat- toneon - bin * equ CSpklat- ;
: measure_a/ds_ucs ( --)
000 ( dummy) pts ( to) shkon ( fr)
?do array i + c@ max loop ( fake minimum_value | dummy) equ UCSamp000 ( dummy) pts ( to) shkon ( fr)
?do array i + c@ UCSamp- = if i + leave then loop ( actual minimum latency) equ UCSpklat255 ( dummy) pts ( to) shkon ( fr)
?do array i + c@ min loop ( fake maximum_value | dummy) equ UCSamp+
000 ( dummy) pts ( to) shkon ( fr)
?do array i + c@ UCSamp+ = if i + leave then loop ( actual maximum latency) equ UCSpklat+
( calculate UCS +criterion ...)
pts shkon - bin * negate equ UCScrit+ ( default_value)
pts ( to) shkon ( fr)
?do array i + c@ baseline critlevel - u<=
if i shkon - bin * equ UCScrit+ leave then loop ( actual crit latency)
( calculate UCS -criterion ...)
pts shkon - bin * negate equ UCScrit- ( default_value)
pts ( to) shkon ( fr)
?do array i + c@ baseline critlevel + swap u<=
if i shkon - bin * equ UCScrit- leave then loop ( actual crit latency)
( corrections: invert calculations for actual values ...)
baseline UCSamp+ - equ UCSamp+
baseline UCSamp- - equ UCSampUCSpklat+ shkon - bin * equ UCSpklat+
UCSpklat- shkon - bin * equ UCSpklat- ;
: get_a/d_data ( --)
trial/-block
case
0 of ( trial)
trl# block ( adr) ram1 1024 cmove
ram1 ( adr) a/d# 1- pts * ( a/d offset) + equ array
endof
1 of ( block)
noop
trl# block ( adr) ram1 1024 cmove
ram2 ( adr) a/d# 1- pts * ( a/d offset) + equ array
endof
2 of ( unit frequencies)
endof
endcase ;
: measure_a/ds ( --) ( calculations for each a/d channel)
#a/d ( to) 0 ( fr)
?do
i 1+ equ a/d# ( useful for parameter passing)
get_a/d_data
measure_baseline
measure_badtime
measure_a/ds_precs
measure_a/ds_cs
measure_a/ds_ucs
print_a/d_data
loop ;
( the following used to be in the file measure3.run )
( unit analysis -- definitions for cluster analysis)
( create cluster )
( ********************************* variables *********************************)
0 equ spikes_this_trial
0 equ max_spikes/cluster
0 equ preCS_spikes/cluster
0 equ ici
0 equ spikes_in_cluster
0 equ start_bin#
0 equ end_bin#
0 equ cluster_duration
0 equ carryover
0 equ total_PCS_spikes
0 equ total_PCS_clusters
0 equ total_PCS_icis
0 equ total_PCS_spikes/cluster
0 equ total_maximum_PCS_spikes/cluster
0 equ total_spikes
0 equ PCS_clusters_this_trial
( ********************************* switches *********************************)
false equ valid_cluster
0 equ total_good_trials
( ****************************** bookkeeping *********************************)
0 equ start_range
0 equ end_range
( *** arrays -- removed from this implementation.)
( size -- removed from this implementation.)
( distribution -- removed from this implementation.)
( empty -- removed from this implementation.)
( ******************************** procedures *********************************)
noop
( ********************************* baseline **********************************)
: get_PCS_spikes ( --) ( used in quietly_analyze_PCS_units)
dummy
toneon ( to) 0 ( fr)
?do ( determine total number of spikes in period in trial ...)
array i + c@ +
loop
( count)
bad_units over u<=
if
true equ bad_trial?
else
false equ bad_trial?
total_PCS_spikes over + equ total_PCS_spikes
total_good_trials 1+ equ total_good_trials
then
total_spikes over + equ total_spikes ( accumulate counts from every trial)
( count) equ spikes_this_trial
noop ;
( *** array management -- removed from this implementation.)
( ici_field -- removed from this implementation.)
( next_ici_field -- removed from this implementation.)
( spikes_in_cluster_field -- removed from this implementation.)
( frequency_field -- removed from this implementation.)
( update_spike_frequency -- removed from this implementation.)
( insert_in_distribution -- removed from this implementation.)
( exact_match -- removed from this implementation.)
( smaller_near_match -- removed from this implementation.)
( larger_near_match -- removed from this implementation.)
( default_match -- removed from this implementation.)
( search_distribution -- removed from this implementation.)
( enter_distribution -- removed from this implementation.)
( ****************************** cluster search *******************************)
: skip_first_cluster ( --) ( I might want to keep this available for this implementation.)
trl# 1 = ( prevent ici calc on very first cluster ...)
if
false equ valid_cluster
else
true equ valid_cluster
then ;
: find_start_of_cluster ( --) ( cannot be removed from this implementation.)
begin ( find start of cluster ...)
bin# end_range u<
array bin# + c@ 0= and
while
bin# 1+ equ bin#
repeat ;
: calculate_ici ( --) ( cannot be removed from this implementation.)
array bin# + c@ 0<> ( calculate ici ...)
if ( if yes, can calculate ici)
bin# equ start_bin# ( information = 1, in_bins)
start_bin# end_bin# - carryover + equ ici ( information = 4, in_ici)
else ( last bin of period has no unit in it)
carryover toneon end_bin# - + equ carryover
0 equ start_bin#
0 equ end_bin#
then ;
: find_end_of_cluster ( --) ( cannot be removed from this implementation.)
0 equ spikes_in_cluster
begin
bin# end_range u<
array bin# + c@ 0<> and
while
spikes_in_cluster array bin# + c@ + equ spikes_in_cluster ( equivalent to c+!)
bin# 1+ equ bin#
repeat ;
( print_information -- removed from this implementation.)
( find_and_print_clusters -- removed from this implementation.)
( find_and_print_PCS_clusters -- removed from this implementation.)
( print_distribution -- removed from this implementation.)
( ************************** unit data distribution ***************************)
1k 2* equ unit_size
create unit_distribution unit_size allot
0 equ unit1_pointer
0 equ unit2_pointer
0 equ unit3_pointer
0 equ unit4_pointer
: empty_unit_distribution ( --)
unit_distribution unit_size erase
0 equ unit1_pointer
0 equ unit2_pointer
0 equ unit3_pointer
0 equ unit4_pointer ;
: set_unit_pointers ( --) ( set pointers into unit_distribution depending on #units)
( used in measure_units, measure_one_unit & review)
#units 0 u> if unit_distribution
equ unit1_pointer then
#units 1 u> if unit_distribution unit_size #units / +
equ unit2_pointer then
#units 2 u> if unit_distribution unit_size #units / 2 * + equ unit3_pointer then
#units 3 u> if unit_distribution unit_size #units / 3 * + equ unit4_pointer then
noop ;
: print_data ( --) ( aka print_unit_distribution; used for debugging)
cr cr " unit 1 > " count type cr
pts 0
?do
unit1_pointer i 2* + @ u.
i 20 mod 0= if cr then
nuf? if leave then
loop
cr cr " unit 2 > " count type cr
pts 0
?do
unit2_pointer i 2* + @ u.
i 20 mod 0= if cr then
nuf? if leave then
loop
cr cr " unit 3 > " count type cr
pts 0
?do
unit3_pointer i 2* + @ u.
i 20 mod 0= if cr then
nuf? if leave then
loop
cr cr " unit 4 > " count type cr
pts 0
?do
unit4_pointer i 2* + @ u.
i 20 mod 0= if cr then
nuf? if leave then
loop
noop ;
0 equ unit1_PCS_Hz
0 equ unit2_PCS_Hz
0 equ unit3_PCS_Hz
0 equ unit4_PCS_Hz
( ********************************** main ************************************)
: get_unit_data ( --)
trial/-block
case
0 of ( trial)
trl# block ( adr) ram1 1024 cmove
ram1 ( adr) unit# 1- #a/d + pts * ( a/d offset) + equ array
endof
1 of ( block)
noop
trl# block ( adr) ram1 1024 cmove
ram2 ( adr) unit# 1- #a/d + pts * ( a/d offset) + equ array
endof
2 of ( unit frequencies)
trl# block ( adr) ram1 1024 cmove
ram1 ( adr) unit# 1- #a/d + pts * ( a/d offset) + equ array
endof
endcase ;
: quietly_analyze_PCS_units ( --) ( used in review)
( does NOT print out and does NOT use debugging words ...)
( to see the results use print_distribution.)
( empty has been removed from this implementation)
#units ( to) 0 ( fr)
?do
i 1+ equ unit#
0 equ start_bin#
0 equ end_bin#
0 equ total_spikes
0 equ max_spikes/cluster
0 equ total_PCS_spikes
0 equ total_PCS_clusters
0 equ total_PCS_icis
0 equ total_good_trials
0 equ carryover
false equ bad_trial?
toneon 256 u< not
if " Distribution array too small " count type abort then ( ... error handler)
#trls ( to) 0 ( fr)
?do ( for every trial ...)
i 1+ equ trl#
get_unit_data
get_PCS_spikes
( find_and_print_PCS_clusters has been removed from this implementation)
nuf? if leave then
loop
( calculate PCS Hz for each unit ...)
1000 ( msec/sec) 10 * ( scale) ( n1)
total_PCS_spikes ( n2)
total_good_trials toneon * bin * ( n3)
*/
5 + 10 / ( answer) ( ... round)
unit#
case
1 of equ unit1_PCS_Hz endof
2 of equ unit2_PCS_Hz endof
3 of equ unit3_PCS_Hz endof
4 of equ unit4_PCS_Hz endof
drop ( default)
endcase
noop
loop ;
: bad_PCS_spikes? ( --)
dummy
toneon ( to) 0 ( fr)
?do ( determine total number of spikes in period in trial ...)
array i + c@ +
loop
( count)
bad_units over u<=
if
true equ bad_trial?
else
false equ bad_trial?
total_PCS_spikes over + equ total_PCS_spikes
total_good_trials 1+ equ total_good_trials
then
( count) equ spikes_this_trial
noop ;
: calculate_Hz ( -- hz)
1000 ( msec/sec) 10 * ( scale) ( n1)
spikes_in_cluster ( n2)
ici cluster_duration + bin * ( n3)
*/
5 + 10 / ( answer) ( ... round)
noop ;
7 equ information ( default) ( used in find_CS_clusters & in measure_units)
: ici_info ( --) 1 equ information ;
: duration_info ( --) 2 equ information ;
: spike_info ( --) 3 equ information ;
: time_info ( --) 4 equ information ;
: bin_info ( --) 5 equ information ;
: raw_info ( --) bin_info ; ( alias)
: start_info ( --) bin_info ; ( alias)
: latency_info ( --) 6 equ information ;
: hz_info ( --) 7 equ information ;
: frequency_info ( --) hz_info ; ( alias)
: freq_info ( --) hz_info ; ( alias)
: special_info 8 equ information ;
: test_info 9 equ information ;
: find_CS_clusters ( dc x y ds0 adr n -- dc x y ds0 adr n|n')
0 equ start_bin#
0 equ end_bin#
0 equ spikes_in_cluster
0 equ carryover
false equ valid_cluster
bad_trial? not
if
0 equ start_range pts equ end_range ( parameters needed for passing to cluster words)
end_range ( to) start_range ( fr)
?do
i equ bin#
find_start_of_cluster
calculate_ici
find_end_of_cluster
spikes_in_cluster ( print)
if
bin# equ end_bin#
end_bin# start_bin# - equ cluster_duration
( valid_cluster \\ this turns out to be unnecessary.)
( if)
( print + in front of significant increase in unit activity ...)
calculate_Hz ( n1)
unit#
case
1 of unit1_PCS_Hz endof
2 of unit2_PCS_Hz endof
3 of unit3_PCS_Hz endof
4 of unit4_PCS_Hz endof
endcase ( n2)
( n1 n2) unit_Hz_criterion * u> ( identify significant unit activity)
if " +" count strcat then
( print - in front of significant decrease in unit activity ...)
calculate_Hz ( n1)
unit#
case
1 of unit1_PCS_Hz endof
2 of unit2_PCS_Hz endof
3 of unit3_PCS_Hz endof
4 of unit4_PCS_Hz endof
endcase ( n2)
( n1 n2) unit_Hz_criterion / swap u> ( identify significant unit activity)
if " -" count strcat then
( put frequency into distribution ...)
calculate_Hz ( n)
unit#
case
1 of unit1_pointer endof
2 of unit2_pointer endof
3 of unit3_pointer endof
4 of unit4_pointer endof
endcase ( ptr) start_bin# 2* + ( adr) !
( choose ONE of the following ...)
information
case
1 of ici ( n) endof ( time of interval between clusters; i.e., inter-cluster-interval)
2 of cluster_duration ( n) endof ( time of unit activity; i.e., duration of cluster)
3 of spikes_in_cluster ( n) endof ( number of spikes to calc frequency)
4 of ici cluster_duration + ( n) endof ( total time to calc frequency)
5 of start_bin# ( n) endof ( latency of cluster from start of trial)
6 of start_bin# ( n)
trl# 1- trialtypetable 1+ + c@
case
ascii 1 of toneon endof
ascii 2 of toneon endof
ascii 3 of shkon endof
( default) toneon
endcase - ( n')
endof ( latency from tone or shkon)
7 of calculate_Hz endof ( Hz)
8 of noop endof ( special)
9 of noop endof ( test)
noop ( default)
endcase
( n) mm>string strcat
( if line length is too long, then print out now and start new line ...)
dup items u>
if
( dc x y ds0 adr n)
TextOut drop
device_cr
"
" string1 strcpy
localdc dup GetCurrentPosition ds0 string1 count
( dc x' y' ds0 adr' n')
then
( \\\\
0 equ carryover \ is this needed? here?)
( else)
( true equ valid_cluster)
( then)
then
( update loop ...)
bin# i +loop
then ;
: measure_units ( --) ( calculations for each a/d channel)
empty_unit_distribution
set_unit_pointers
#units ( to) 0 ( fr)
?do
i 1+ equ unit#
get_unit_data
bad_PCS_spikes?
legendfont
lightred coloring
device_cr
localdc dup GetCurrentPosition ds0 ( dc x y ds0)
trial/-block
case
0 of ( trial)
" unit # " string1 strcpy
string1 count unit# mm>string strcat
information 7 =
if ( print baseline frequency for each unit ...)
" (" count strcat
unit#
case
1 of unit1_PCS_Hz endof
2 of unit2_PCS_Hz endof
3 of unit3_PCS_Hz endof
4 of unit4_PCS_Hz endof
endcase
mm>string strcat
" Hz) " count strcat
then
" ... " count strcat
bad_trial? if " bad units " count strcat then
endof
1 of ( block)
" block average " string1 strcpy ( this may not seem efficient but it is necessary)
string1 count
( for printing whole line to printer.)
endof
2 of ( unit frequencies) ( if measure not done in dave.4th, this is never done for source=frequencies.)
" unit # " string1 strcpy
string1 count unit# mm>string strcat
information 7 =
if ( print baseline frequency for each unit ...)
" (" count strcat
unit#
case
1 of unit1_PCS_Hz endof
2 of unit2_PCS_Hz endof
3 of unit3_PCS_Hz endof
4 of unit4_PCS_Hz endof
endcase
mm>string strcat
" Hz) " count strcat
then
" ... " count strcat
endof
endcase
( dc x y ds0 adr n)
find_CS_clusters ( get results)
( dc x y ds0 adr n') TextOut drop ( print whole line)
loop ;
: measure_one_unit ( --) ( calculations for one unit channel. Must set unit#.)
empty_unit_distribution
set_unit_pointers
( 2 equ unit# \\ debugging)
get_unit_data
bad_PCS_spikes?
0 equ start_bin#
0 equ end_bin#
0 equ spikes_in_cluster
0 equ carryover
false equ valid_cluster
bad_trial? not
if
0 equ start_range pts equ end_range ( parameters needed for passing to cluster words)
end_range ( to) start_range ( fr)
?do
i equ bin#
find_start_of_cluster
calculate_ici
find_end_of_cluster
spikes_in_cluster ( print)
if
bin# equ end_bin#
end_bin# start_bin# - equ cluster_duration
( put frequency into distribution ...)
calculate_Hz ( n)
unit#
case
1 of unit1_pointer endof
2 of unit2_pointer endof
3 of unit3_pointer endof
4 of unit4_pointer endof
endcase ( ptr) start_bin# 2* + ( adr) !
then
( update loop ...)
bin# i +loop
then
noop ;
: measure ( --) measure_a/ds measure_units ;
( the following used to be in the file draw.run )
: hollowed_rectangle ( dc x1 y1 x2 y2 -- dummy) ( draw hollow rectangle.)
equ y2 equ x2 equ y1 equ x1 ( dc) drop
y1 y2 <>
if ( only draw hollow if data exists \\ prevents score line over CS & UCS marks)
localdc x1 y1 Moveto 2drop
localdc x2 y1 LineTo drop
localdc x2 y2 LineTo drop
localdc x1 y2 LineTo drop
localdc x1 y1 LineTo drop
then
0 ( dummy) ;
: filled_rectangle ( dc x1 y1 x2 y2 -- dummy) ( draws filled rectangle.)
equ y2 equ x2 equ y1 equ x1 ( dc) drop
localdc x1 y1 Moveto 2drop
x2 x1
?do
localdc i y1 Moveto 2drop
localdc i y2 LineTo drop
loop
0 ( dummy) ;
: draw_a/ds ( --)
( for each a/d channel ...)
#a/d ( to) 0 ( fr)
?do ( index is a/d channel number 0 - #a/d)
i 1+ equ a/d# ( useful for parameter passing)
get_a/d_data
blue coloring
( select coordinate origin ... )
localdc 0 ( x) offset ( y) SetViewportOrg 2drop
( draw a/d channel ...)
pts ( to) 0 ( fr)
?do ( index is data bin number, used to get into array)
i 0= ( true if first data point)
if
localdc 0 ( x) array i + c@ ( y)
j 0 = if a/d1x a/d1/ */ then ( magnification of a/d1 ...)
j 1 = if a/d2x a/d2/ */ then
j 2 = if a/d3x a/d3/ */ then
j 3 = if a/d4x a/d4/ */ then
1+ ( magical offset; otherwise no plot if y is equal to zero)
MoveTo 2drop
else ( false for all other data points)
localdc i xscalex * ( x2) array i + c@ ( y2)
j 0 = if a/d1x a/d1/ */ then ( magnification of a/d1 ...)
j 1 = if a/d2x a/d2/ */ then
j 2 = if a/d3x a/d3/ */ then
j 3 = if a/d4x a/d4/ */ then
1+ ( magical offset; otherwise no plot if y is equal to zero)
LineTo drop
then
loop
( NOTE: LineTo seems to automatically advance x,y whereas Rectangle does not seem to.)
( print data legend ...)
legendfont
lightred coloring
localdc dup GetCurrentPosition ds0 " a/d # " count i 1+ s>d <# #s #> strcat TextOut drop
( select offset for next picture ...)
0 ( dummy)
pts 0
?do
array i + c@ max
loop
( maximum_value | dummy)
i 0 = if a/d1x a/d1/ */ then
i 1 = if a/d2x a/d2/ */ then
i 2 = if a/d3x a/d3/ */ then
i 3 = if a/d4x a/d4/ */ then
( scaled_value) 20 max ( at least this much space) offset + equ offset
loop ;
true equ style
: filled ( --) true equ style ;
: hollowed ( --) false equ style ;
: draw_units ( --)
( additional space required between a/d and units ...)
offset 20 + equ offset
( for each unit channel ...)
#units 0
?do
i 1+ equ unit#
get_unit_data
blue coloring
( select coordinate origin ...)
( select offset for next picture ...)
10 ( dummy) ( give at least this amount of space if no units)
pts 0
?do
array i + c@ max
loop
( maximum_value | dummy)
i 0 = if unit1x unit1/ */ then
i 1 = if unit2x unit2/ */ then
i 2 = if unit3x unit3/ */ then
i 3 = if unit4x unit4/ */ then
( scaled_value)
10 + ( at least this much space between unit pictures) offset + equ offset
localdc 0 ( x) offset ( y) SetViewportOrg 2drop
( draw unit channels ...)
pts 0
?do
i equ bin#
localdc i xscalex * ( x1) 0 ( y1) i 1+ xscalex * ( x2) array i + c@ ( y2)
j 0 = if unit1x unit1/ */ then ( magnification of unit1 ...)
j 1 = if unit2x unit2/ */ then
j 2 = if unit3x unit3/ */ then
j 3 = if unit4x unit4/ */ then
negate ( with setviewportorg above, negate plots units up rather than down)
( dc x1 y1 x2 y2) ( NOTE: y2 is the value to plot.)
( determine hollow/filled ...)
dup 0= if hollowed then ( reset to hollowed if no units)
unit# ( check latency in unit_distribution ...)
case
1 of unit1_pointer bin# 2* + endof
2 of unit2_pointer bin# 2* + endof
3 of unit3_pointer bin# 2* + endof
4 of unit4_pointer bin# 2* + endof
endcase ( adr) @ ( n1)
unit# ( ... get criterion ...)
case
1 of unit1_PCS_Hz endof
2 of unit2_PCS_Hz endof
3 of unit3_PCS_Hz endof
4 of unit4_PCS_Hz endof
endcase unit_Hz_criterion * ( n2)
( n1 n2) u> ( make comparison) trial/-block 1 = or ( always fill if block display)
if ( beginning of cluster, meets criterion ...)
filled
else ( could be within criterial cluster ...)
style ( if units in same filled cluster then keep filled)
if
filled
else ( if units in unfilled cluster then keep unfilled)
hollowed
then
then
( execute drawing ...)
style
if
( dc x1 y1 x2 y2) filled_rectangle ( flag) drop
else
( dc x1 y1 x2 y2) hollowed_rectangle ( flag) drop
then
noop
loop
( draw underline and stimulus marks ...)
trl# 1- trialtypetable 1+ + c@
case
ascii 1 ( tone alone marks)
of
localdc 0 ( x1) 2 ( y1) toneon xscalex * ( x2) 0 ( y2) filled_rectangle drop ( draw underline)
localdc toneon 1+ xscalex * ( x1) 2 ( y1) pts xscalex * ( x2) 0 ( y2) filled_rectangle drop
endof
ascii 2 ( paired tone and air marks)
of
localdc 0 ( x1) 2 ( y1) toneon xscalex * ( x2) 0 ( y2) filled_rectangle drop ( draw underline)
localdc toneon 1+ xscalex * ( x1) 2 ( y1) shkon xscalex * ( x2) 0 ( y2) filled_rectangle drop
localdc shkon 1+ xscalex * ( x1) 2 ( y1) pts xscalex * ( x2) 0 ( y2) filled_rectangle drop
endof
ascii 3 ( air alone marks)
of
localdc 0 ( x1) 2 ( y1) shkon xscalex * ( x2) 0 ( y2) filled_rectangle drop ( draw underline)
localdc shkon 1+ xscalex * ( x1) 2 ( y1) pts xscalex * ( x2) 0 ( y2) filled_rectangle drop
endof
endcase
( move to right of plot and print info ...)
localdc pts xscalex * ( x) 0 ( y) MoveTo 2drop ( NOTE: Rectangle must not advance x,y automatically
like LineTo seems to.)
legendfont
lightred coloring
localdc dup GetCurrentPosition ds0 " unit # " count i 1+ s>d <# #s #> strcat TextOut drop
loop ;
0 equ mark
: timing_marks ( --) ( marks for time from trial onset ...)
( additional space for coordinate ...)
offset printing if 100 else 20 then + equ offset
localdc 0 ( x) offset ( y) SetViewportOrg 2drop
black pen
pts ( to) 0 ( fr)
?do
i 0=
if
localdc 0 0 Moveto 2drop
else
localdc i xscalex * 0 LineTo drop
localdc i xscalex * mark negate LineTo drop
localdc i xscalex * mark 2* LineTo drop
localdc i xscalex * 0 Moveto 2drop
then
100 bin / ( approximately every 100 msec)
+loop
localdc pts xscalex * 0 Lineto drop
( timing legend ...)
legendfont
lightred coloring
localdc dup GetCurrentPosition ds0
" " string1 strcpy
string1 count 100 bin / bin * mm>string strcat
" msec ticks" count strcat TextOut drop
( update coordinates ...)
offset 20 + equ offset ;
: cs_marks ( --) ( CS marks ...)
( additional space for coordinate ...)
offset printing if 40 else 20 then + equ offset
localdc 0 ( x) offset ( y) SetViewportOrg 2drop
black pen
localdc 0 0 Moveto 2drop
localdc toneon xscalex * 0 LineTo drop
localdc toneon xscalex * mark negate LineTo drop
localdc toneoff xscalex * mark negate LineTo drop
localdc toneoff xscalex * 0 LineTo drop
localdc pts xscalex * 0 LineTo drop
( CS legend ...)
legendfont
lightred coloring
localdc dup GetCurrentPosition ds0 " CS " count TextOut drop
( update coordinates ...)
offset 20 + equ offset ;
: ucs_marks ( --) ( UCS marks ...)
( additional space for coordinate ...)
offset printing if 40 else 20 then + equ offset
localdc 0 ( x) offset ( y) SetViewportOrg 2drop
black pen
localdc 0 0 Moveto 2drop
localdc shkon xscalex * 0 LineTo drop
localdc shkon xscalex * mark negate LineTo drop
localdc shkoff xscalex * mark negate LineTo drop
localdc shkoff xscalex * 0 LineTo drop
localdc pts xscalex * 0 LineTo drop
( UCS legend ...)
legendfont
lightred coloring
localdc dup GetCurrentPosition ds0 " UCS" count TextOut drop
( update coordinates ...)
offset 20 + equ offset ;
: draw_cursors ( --) ( the following draws the cursor marks ...)
printing if 15 else 5 then equ mark
timing_marks
trl# 1- trialtypetable 1+ + c@
case
ascii 1 of cs_marks
endof
ascii 2 of cs_marks ucs_marks endof
ascii 3 of
ucs_marks endof
endcase ;
( the following used to be in the file draw2.run )
( display frequency x latency unit data)
0 equ tempx
0 equ tempy
0 equ actual_y
3 equ radius
: symbol ( --)
( draw up-down line ...)
( localdc tempx tempy Lineto drop)
( localdc tempx tempy 6 + Lineto drop)
( localdc tempx tempy 6 - Lineto drop)
localdc ( dc)
tempx radius printing if 2 * then - ( x1)
tempy radius printing if 2 * then - ( y1)
tempx radius printing if 2 * then + ( x2)
tempy radius printing if 2 * then + ( y2)
( dc x1 y1 x2 y2)
( significant? ...)
actual_y ( n1)
unit#
case
1 of unit1_PCS_Hz endof
2 of unit2_PCS_Hz endof
3 of unit3_PCS_Hz endof
4 of unit4_PCS_Hz endof
endcase unit_Hz_criterion * ( n2)
( dc x1 y1 x2 y2 n1 n2) u>
if ( draw hollow/filled with coloring ...)
lightred coloring filled_rectangle drop
else
blue coloring hollowed_rectangle drop
then
localdc tempx tempy MoveTo 2drop
blue coloring
noop ;
false equ moved?
: get_unit_pointer ( -- adr)
unit#
case
1 of unit1_pointer endof
2 of unit2_pointer endof
3 of unit3_pointer endof
4 of unit4_pointer endof
endcase ( adr)
noop ;
: (draw_Hz) ( --) ( draw one channel; set unit# before calling this routine.)
false equ moved?
pts ( to) 0 ( fr)
?do
get_unit_pointer ( adr) i 2* + @ 0<>
if ( found data point ...)
localdc ( dc) i xscalex * ( x) get_unit_pointer i 2* + @ dup equ actual_y negate ( y)
( dc x y) hz1x * hz1/ / ( scaled y) printing if 3 * then ( scaled for printing)
2dup equ tempy equ tempx
moved?
if ( all subsequent data points)
( dc x y) LineTo drop symbol
else ( first data point)
( dc x y) MoveTo 2drop symbol
true equ moved?
then
then
loop
noop ;
: histograms ( --) 0 equ mode ; ( select histogram display for trial unit data.)
: histogram ( --) histograms ; ( alias)
: frequencies ( --) 1 equ mode ; ( select frequency display for trial unit data.)
: frequency ( --) frequencies ; ( alias)
: draw_Hz ( --) ( draws frequencies for current trial for all units.)
offset 100 + equ offset
#units ( to) 0 ( fr)
?do ( index is unit number 0 - #units)
i 1+ equ unit# ( useful for parameter passing)
blue coloring
localdc ( dc) 0 ( x) offset ( y) printing if 4 * then SetViewportOrg 2drop
(draw_Hz)
offset 50 + equ offset
loop
noop ;
: unit1 ( --) 1 equ unit# ( _for_display) ;
: unit2 ( --) 2 equ unit# ( _for_display) ;
: unit3 ( --) 3 equ unit# ( _for_display) ;
: unit4 ( --) 4 equ unit# ( _for_display) ;
: multiple_Hz ( --)
( draws range of frequencies { start end} for selected unit { unit1 unit2 unit3 unit4} )
offset 200 + equ offset
trl# equ _trl#
end 1+ start u>
if ( make sure do-loop limits are correct ...)
end 1+ ( to) start ( fr)
?do
i equ trl#
trl# 1- trialtypetable 1+ + c@ tones =
trl# 1- trialtypetable 1+ + c@ pairs = or
trl# 1- trialtypetable 1+ + c@ airs = or
if ( trial type matches request, therefore include this trial in display ...)
localdc ( dc) 0 ( x) offset ( y) printing if 4 * then SetViewportOrg 2drop
get_unit_data
measure_one_unit
(draw_Hz)
offset stagger + equ offset
then
loop
else
localdc dup GetCurrentPosition ds0 " Error! Check order and values of start and end trials " count
( dc x' y' ds0 adr' n') TextOut drop
then
_trl# equ trl#
noop ;
( the following used to be in the file graphics.run )
: zero ( --) ram2 2048 0 fill 0 equ counter ;
: (add) ( --)
counter 1+ equ counter
1024 ( to) 0 ( fr)
?do
ram2 i 2* + @ ( current value) ram1 i + c@ + ( add) ram2 i 2* + ! ( to)
loop ;
: add ( --) ( use n1 n2 through to set end, start.)
trl# equ _trl#
end 1+ start
?do
i equ trl#
trl# 1- trialtypetable 1+ + c@ tones =
trl# 1- trialtypetable 1+ + c@ pairs = or
trl# 1- trialtypetable 1+ + c@ airs = or
if ( trial type matches request, therefore include this trial in display ...)
get_a/d_data
(add)
then
loop
_trl# equ trl#
get_a/d_data ;
: (subtract) ( --)
counter 1- equ counter
1024 ( to) 0 ( fr)
?do
ram2 i 2* + @ ( current value) ram1 i + c@ - ( minus) ram2 i 2* + ! ( to)
loop ;
: subtract ( --) ( use n1 n2 through to set end, start.)
trl# equ _trl#
end 1+ start
?do
i equ trl#
trl# 1- trialtypetable 1+ + c@ tones =
trl# 1- trialtypetable 1+ + c@ pairs = or
trl# 1- trialtypetable 1+ + c@ airs = or
if ( trial type matches request, therefore include this trial in display ...)
get_a/d_data
(subtract)
then
loop
_trl# equ trl#
get_a/d_data ;
: average ( --)
pts #a/d * ( to) 0 ( fr) ( average the a/d data)
?do
ram2 i 2* + @ counter / ( mean) ram2 i + c! ( to)
loop
0 equ counter
1024 ( to) pts #a/d * ( fr) ( the remaining space is cumulative unit data)
?do
ram2 i 2* + @ ( cumulative) ram2 i + c! ( to)
loop
noop ;
( *** this is not loaded >>> include go.run ...)
( analyzes PCS activity for Claire)
( i.e., go<return> prints out total PCS units for each trial and for every unit)
( this gives an idea of PCS unit activity.)
: process ( --)
localdc logpixelsx GetDeviceCaps equ xpixels/inch
localdc logpixelsy GetDeviceCaps equ ypixels/inch
localdc mm_text ( mm_loenglish) SetMapMode drop
20 equ offset ( set y position of plot)
.trial#
.info
.cmds
trial/-block
case
0 of ( trial)
measure
printing if draw_cursors then
draw_a/ds
mode 0= ( selected by histogram|histograms {default} versus frequency|frequencies)
if
draw_units
else
draw_Hz
then
draw_cursors
endof
1 of ( block)
measure
printing if draw_cursors then
draw_a/ds
draw_units
draw_cursors
endof
2 of ( unit frequency)
( measure)
multiple_Hz
draw_cursors
endof
endcase
localdc mm_text SetMapMode drop ;
( printer support)
0 EQU PDC
( DC for printing)
0 EQU CHARY ( character height, printer font)
0 EQU CHARX ( average character width, printer font)
0 EQU PAGEY ( total page height)
0 EQU PAGEX ( total page width)
0 EQU HORZMARG ( width of each side margin)
0 EQU VERTMARG ( height of top & bottom margins)
CREATE DOCINFO 10 , 0 , 0 , 0 , 0 , ( Data structure used by various Windows 3.1 printing APIs)
( --- ; process File-Print command)
: DOPRINT
PRINTDLG ( show print dialog to user)
IF
true equ printing
2DROP ( discard flags ) EQU PDC ( save printer DC)
3DROP ( discard page numbers etc. )
" Print Test" ASCIIZ DOCINFO 2+ ! DS0 DOCINFO 4 + ! ( print job name into DOCINFO structure )
PDC DS0 DOCINFO StartDoc DROP ( start print job, start first page)
PDC StartPage DROP
( make drawing ...)
pdc equ localdc
xscalex a/d1x a/d2x a/d3x a/d4x unit1x unit2x unit3x unit4x ( save values)
xscalex 3 * equ xscalex
a/d1x 5 * equ a/d1x a/d2x 5 * equ a/d2x a/d3x 5 * equ a/d3x a/d4x 5 * equ a/d4x
unit1x 5 * equ unit1x unit2x 5 * equ unit2x unit3x 5 * equ unit3x unit4x 5 * equ unit4x
process
equ unit4x equ unit3x equ unit2x equ unit1x equ a/d4x equ a/d3x equ a/d2x equ a/d1x equ xscalex (
restore values)
PDC EndPage DROP ( clean up everything)
PDC EndDoc DROP ( end print job)
PDC DeleteDC ( discard printer DC)
false equ printing
THEN ;
: ERRORBOX ( ^str --) ( display error message and OK button in message box)
" Error Condition" [ MB_ICONHAND MB_OK OR ] LITERAL MSGBOX DROP ;
: WNDPROC ( -- dn) ( message handler for the frame window )
wMsg CASE
WM_PAINT ( returns hDC, psRect, lpPS)
OF ( --; process WM_PAINT message for frame window)
hDC equ localdc
process
ENDOF
WM_SIZE
OF ( change in window size, force complete repaint)
MAINWIN WREPAINT
ENDOF
WM_COMMAND
OF ( --; This routine handles WM_COMMAND messages from the frame window's menu.)
wParam CASE
IDM_FILEPRINT OF DOPRINT ENDOF
IDM_FILEEXIT
OF ( send message to frame window)
WM_CLOSE ( msg --) MAINWIN WCB>HWND SWAP 0 0. SendMessage 2DROP
ENDOF
idm_openfile of selectfile endof
idm_start of trl# 1 <> if 1 equ trl# mainwin wrepaint then endof
idm_block- of trl# #t/blk - 0> if #t/blk negate trl# 1+ + equ trl# mainwin wrepaint then endof
idm_trial- of trl# 1 <> if trl# 1- equ trl# mainwin wrepaint then endof
idm_stop of ( currently has no function; mainwin wrepaint) endof
idm_trial+ of trl# #trls <> if trl# 1+ equ trl# mainwin wrepaint then endof
idm_block+ of trl# #t/blk + #trls 1+ u< if trl# #t/blk + equ trl# mainwin wrepaint then endof
idm_end
of #trls trl# <> if #trls equ trl# mainwin wrepaint then endof
idm_jump
of
trl# ( n) ( used to check to see if trial number has actually changed)
jumpdlg ['] jumpprocedure rundlg
if
jump# @
dup #trls u<= over 1 swap u<= and ( make sure 1 <= jump# @ <= #trls)
if ( n) equ trl# else drop then
then
( n) trl# <> if mainwin wrepaint then ( repaint if trial # has changed)
endof
idm_interpretter
of
interpretterdlg ['] interpretterprocedure rundlg
if
interpretterbuffer eval
mainwin wrepaint
then
endof
idm_source
of
trial/-block
case ( rotate through selection of sources ...)
0 of 1 equ trial/-block endof
1 of 2 equ trial/-block endof
2 of 0 equ trial/-block endof
endcase
mainwin wrepaint
endof
(
idm_average)
(
of )
(
averagedlg ['] averageprocedure rundlg)
(
if )
(
noop)
(
then)
(
mainwin wrepaint )
(
endof)
idm_info
of
info 0= equ info ( clever way to toggle switch)
mainwin wrepaint
endof
idm_cmds
of
cmds 0= equ cmds ( clever way to toggle switch)
mainwin wrepaint
endof
" Command not implemented" ERRORBOX
ENDCASE
ENDOF ( menu command message)
WM_DESTROY
OF ( kill message loop)
0 PostQuitMessage
ENDOF
DEFMSGHANDLER EXIT ( set by setmsghandler, the default case passes message to
DefWindowProc( )
ENDCASE
0 0 ; ( double value to return from this message handler back to window loop )
: review ( --) ( "main word" creates the frame window and then enters message loop)
( bob \\ select runtime/summary parameters: bob, xty, ben )
#trls 0= pts 0= if " Select parameters first " count type abort then
selectfile ( open data file )
cr " Please wait while analyzing baseline units. " count type cr
quietly_analyze_PCS_units
" End baseline unit analysis. " count type cr
1 equ trl#
( figure out preliminaries for unit data ...)
empty_unit_distribution
set_unit_pointers
['] WNDPROC MAINWIN SETMSGHANDLER ( install msg handler, returns hWnd, wMsg, wParam,
lParam, pWCB)
( getmsghandler )
" Data Review Program" MAINWIN WSETNAME ( set frame window caption)
( wsetpos)
( wsetsize)
( wsetstyle)
" APPICON" MAINWIN WLOADICON DROP ( wloadmenu | wsetmenu; set icon)
( wsetparent)
MAINWIN WCREATE 0= ( create main window)
IF " Can't create frame window!" ERRORBOX 0 RETURN THEN
100 100 mainwin wsetpos
pts pts 5 / + xscalex * ( x) 650 ( y) mainwin wsetsize
( whide)
( wminimize | wmaximize)
( wrestore )
APPMENU MAINWIN WSETMENU FALSE = ( set frame window menu)
IF " Can't create menu!" ERRORBOX 0 RETURN THEN
MAINWIN WSHOW ( display frame window)
( winsmgloop | the following ...)
( begin ... processwinmsg | processrawmsg | peekwinmsg | peekrawmsg ... until)
WINMSGLOOP ( wait for WM_QUIT message)
MAINWIN WCLOSE
flush
QUIT ( 0 RETURN ) ;
CR
CR .( To run the review program, enter parameters then type: review <Enter> )
CR
( the end )
Cluster analysis source code: cluster.txt
This second cluster-related file (cluster.txt) is used to give a print out, on a trial-by-trial basis, of
the information about each cluster found in every trial. Cluster analysis is actually implemented in the
review program (dave.txt). This information can be useful in deciding whether unit activity is significantly
related to behavior. This information is also overwhelming, however, and you are going to find more
clusters than you know what to do with. The program identifies significant clusters compared with
baseline, however it itself does not determine whether that activity is or is not significantly related to
behavior. The problem with cluster analysis is how to cross this last step. One way to continue the
analysis would be to correlate the first, second, third, etc. cluster after CS onset (or before US onset) with
the onset of the behavioral response versus with the onset of the CS or US (i.e., is it behavior-related or
stimulus-related?). When unit activity is found to be consistent (i.e., to have a high correlation with
behavior or a stimulus event) then it becomes interesting to know about the latencies and strength of the
unit response.
( cluster.txt )
( copied from cluster.bak)
( this program is designed to give a printout of unit clusters for every trial.)
( a cluster is defined as the bins that make up a period of continuous unit activity.) ( the latency of
the cluster is the first bin where unit activity begins.) ( to calculate the frequency, the total amount of unit
activity that makes up the cluster is divided by the time { the time occupied by a cluster plus the time
before the cluster when no unit activity happened } and scaled for 1 second to report it in Hz.)
( commands are indicated at the end of this file and are printed out when the program is
compiled.)
( significant clusters are indicated by +/- signs with the hz_info option, where a comparison of
each cluster is made against the average frequency of baseline preCS activity for the BLOCK or
SESSION multiplied by a criterion factor.) ( BLOCK is chosen with by_block; SESSION is chosen with
by_session.) ( cluster.txt, therefore, is suited to analyzing data where manipulations are made on a blockby-block or session basis.) ( the frequency in the baseline preCS activity is calculated on the basis of the
number of units that make up a cluster and the time occupied by the cluster and the preceeding period -that is, the very first cluster is NOT counted in the calculation { because the preceding period is
indeterminate } and therefore at least two clusters must be identified in the block before the preCS
frequency can be calculated.) ( this is a more conservative and more accurate measure of the preCS
frequency than is used by the review program.)
( note that baseline frequencies and significances are calculated differently between cluster.txt
and the review program.) ( in the review program, each cluster is compared with the average frequency of
baseline preCS activity {total activity, not clusters} for the SESSION multiplied by a criterion factor.) ( in
the review program, preCS activity is simply calculated by counting all unit activity in the preCS periods.) (
this calculation includes, therefore, the quiet periods before the first cluster appears in the day, and the
quiet period after the last cluster has been found.)
create marker
0 equ total_PCS_spikes_in_block
0 equ total_PCS_spikes_in_session
0 equ ici
false equ CS?
false equ UCS?
( variables for figuring out PCS Hz ...)
0 equ end_of_first_cluster_in_block
0 equ end_of_last_cluster_in_block
\ 0 equ trial_of_first_cluster_in_block ( debugging)
\ 0 equ trial_of_last_cluster_in_block ( debugging)
0 equ pcs_time
0 equ #clusters
0 equ #spikes
0 equ pcs_hz ( temporary storage for block and session pcs frequency calculations)
: is_this_a_good_trial? ( --)
( count total number of spikes in PCS period ...)
dummy
toneon ( to) 0 ( fr)
?do array i + c@ + loop ( count)
( determine if too many PCS spikes ...)
bad_units over ( bad_units count) u<=
if ( bad trial ...)
true equ bad_trial? " bad units " count type
else ( good trial; update counters ...)
false equ bad_trial?
total_PCS_spikes_in_block over + equ total_PCS_spikes_in_block ( equivalent to +!)
total_PCS_spikes_in_session over + equ total_PCS_spikes_in_session ( ~ +!)
total_good_trials
1+ equ total_good_trials ( ~ to +!)
then
( count) drop ;
0 equ items
: check_items ( n--n) ( needed for HP laserjet printout ...)
dup 100 / 0<>
if ( true if >= to 100)
items 3 + equ items
else
dup 10 / 0<> ( true if >= to 10 AND ALSO less than 100)
if items 2 + equ items
else items 1 + equ items
then
then
items 82 u> printing and
if 0 equ items cr 10 spaces then ;
0 equ session
: by_session true equ session ; ( true = compare cluster frequency with session frequency)
: by_block false equ session ; ( false = compare cluster frequency with block frequency)
by_block ( default)
: hertz ( -- hz) ( select session or block hz for comparison with cluster's hz)
session case
true of ( session analysis hz)
unit# case
1 of unit1_PCS_Hz endof
2 of unit2_PCS_Hz endof
3 of unit3_PCS_Hz endof
4 of unit4_PCS_Hz endof
endcase
endof
false of ( block analysis hz) pcs_hz endof
endcase
100 / ( necessary scaling to compare with hz calculated for each cluster)
noop ;
0 equ PCS_clusters_this_trial
: find_and_print_clusters ( --) ( for every trial ...)
( initialize variables ...)
false equ CS?
false equ UCS?
0 equ items
0 equ PCS_clusters_this_trial
0 equ ici
0 equ start_range pts equ end_range ( parameters needed for passing to cluster words)
( identify clusters ...)
end_range ( to) start_range ( fr)
?do
( where does cluster begin? ...)
i equ bin# ( bin# used for parameter passing)
find_start_of_cluster
( set start_bin# if cluster has been found ...)
array bin# + c@ 0<>
if bin# equ start_bin# then
( calculate ici if previous cluster has been found ...)
ici 0=
if ( no, previous cluster was not found)
bin# equ ici
else ( yes, previous cluster was found; calculate ici)
bin# end_bin# - equ ici
then
( where does cluster end? ...)
find_end_of_cluster
( is there a valid cluster? ...)
start_bin# pts <>
if ( yes, valid cluster; otherwise, no action)
CS? not toneon start_bin# u<= and ( yes = cluster found in CS period)
if true equ CS? ascii / emit space then
UCS? not shkon start_bin# u<= and ( yes = cluster found in UCS period)
if true equ UCS? ascii / emit ascii / emit space then
CS? not ici 0<> ( only count valid ici) and ( yes =PCS cluster)
( this test must come after above tests for CS and UCS)
if PCS_clusters_this_trial 1+ equ PCS_clusters_this_trial ( needed to calc PCS Hz) then
spikes_in_cluster 0<>
if
( needed to calculate frequency ...)
bin# equ end_bin#
end_bin# start_bin# - equ cluster_duration
( choose display type ...)
information case
1 of ( ici) ici 0<> if ici check_items u. then endof
2 of ( duration) cluster_duration check_items u. endof
3 of ( spikes) spikes_in_cluster check_items u. endof
4 of ( time) start_bin# bin * check_items u. endof
5 of ( bin) start_bin# check_items u. endof
6 of ( latency) start_bin# ( n)
CS?
if ( yes, passed into CS period)
toneon else ( no, still in PCS period)
ascii - emit
items 1 + equ items
toneon swap then
( n|n') bin * check_items u.
endof
7 of ( frequency) calculate_Hz
dup hertz unit_Hz_criterion * u>
if ascii + emit items 1+ equ items then
dup hertz unit_Hz_criterion / swap u>
if ascii - emit items 1+ equ items then
check_items u. endof
8 of ( special)
( latency) start_bin# ( n)
CS?
if ( yes, passed into CS period)
toneon else ( no, still in PCS period)
ascii - emit
items 1 + equ items
toneon swap then
( n|n') bin * check_items ( n|n') s>d <# #s #> type
( separator)
ascii , emit
( frequency) calculate_Hz
dup hertz unit_Hz_criterion * u>
if ascii + emit items 1+ equ items then
dup hertz unit_Hz_criterion / swap u>
if ascii - emit items 1+ equ items then
check_items u.
endof
9 of ( test) noop endof
noop ( default)
endcase
then
then
bin# i - ( update loop counter)
+loop ;
: freq ( time count -- pcs_hz) ( calculate hz)
10 * 10000 um* rot bin * ( denominator) dup >r um/mod ( remainder quotient)
swap 2* r> ( quotient remainder*2 denominator) / + ;
: .hz ( pcs_hz --) ( print hz)
s>d <# # # ascii . hold #s #> type " Hz " count type ;
: print_block ( --)
cr
trl# #t/blk mod 0= ( every block)
if
" Block number " count type trl# #t/blk / u.
\
" total PCS spikes = " count type total_PCS_spikes_in_block u.
\
0 equ total_PCS_spikes_in_block
\
cr
\
" first cluster = " count type end_of_first_cluster_in_block u.
\
\
\
\
\
\
\
\
\
\
\
" , trial = " count type trial_of_first_cluster_in_block u.
cr
" last cluster = " count type end_of_last_cluster_in_block u.
" , trial = " count type trial_of_last_cluster_in_block u.
cr
" # pcs clusters = " count type #clusters u. ( NOTE: wrong count)
cr
" # pcs spikes = " count type #spikes u.
cr
" pcs time = " count type pcs_time u.
cr
2 spaces
( compare block hz with session hz ...)
" Block pcs Hz = " count type
( calculate block hz ...)
pcs_time #spikes ( difference count) freq ( blockhz)
( select session hz ...)
unit# case
1 of unit1_PCS_Hz endof
2 of unit2_PCS_Hz endof
3 of unit3_PCS_Hz endof
4 of unit4_PCS_Hz endof
endcase
( blockhz sessionhz)
( print +/- if block is significantly different from session ...)
2dup
unit_Hz_criterion * u>
if ascii + emit then
unit_Hz_criterion / swap u>
if ascii - emit then
( print block hz ...)
pcs_time #spikes ( difference count) freq .hz ( calculate & print hz)
cr cr
then ;
: PCS_Hz_in_this_trial ( --)
2 PCS_clusters_this_trial u<= ( must have at least 2 clusters to calculate hz)
if ( yes, at least one cluster in preCS period)
18 check_items drop ( make sure enough room at end of line or force next line)
" (PCS = " count type
( find start of first cluster ...)
toneon ( to) 0 ( fr)
?do
array i + c@ 0<> if i leave then
loop ( i)
( find end of first cluster ...)
( i) toneon swap
?do
array i + c@ 0= if i ( i1) leave then
loop ( i1) ( = beginning of valid counting period)
( find end of the last cluster ...)
0 ( to) toneon 1- ( correction for backwards loop) ( fr)
?do
array i + c@ 0<> if i ( i2) leave then
-1
+loop ( i2)
1+ ( correction)
( i1 i2') ( = beginning and end of valid counting period)
swap 2dup - -rot ( i2'-i1=difference i2' i1)
( count units in valid counting period ...)
dummy ( n)
-rot ( difference dummy i2 i1)
?do
array i + c@ + loop ( difference count)
( figure out PCS frequency ...)
freq .hz ( calculate & print hz)
ascii ) emit
else ( not enough clusters to calculate PCS Hz -- need at least two clusters)
" (cannot calculate PCS Hz)" count check_items type
then
noop ;
: test_for_good_trial? ( --) ( is this a good trial? ...)
dummy
toneon ( to) 0 ( fr) ( count total number of spikes in PCS period ...)
?do array i + c@ + loop ( count)
bad_units swap ( bad_units count) u<= ( too many PCS spikes?)
if true equ bad_trial? else false equ bad_trial? then ;
0 equ analysis ( session analysis)
1 equ analysis ( block analysis)
: PCS_block|session_analysis ( --)
( select for block or session analysis -- PCS_block_analysis vs. PCS_session_analysis)
( figure out PCS frequency)
(
analysis is done for a block of trials or for the whole session)
(
returns pcs_time, #spikes -- needed to calculate pcs frequency)
(
returns pcs_hz or unit1_PCS_Hz ...)
0 equ end_of_first_cluster_in_block
0 equ end_of_last_cluster_in_block
\ 0 equ trial_of_first_cluster_in_block ( debugging)
\ 0 equ trial_of_last_cluster_in_block ( debugging)
0 equ pcs_time
0 equ #clusters
0 equ #spikes
analysis case
0 of ( session analysis range) #trls ( to)
0 ( fr) endof
1 of ( block analysis range) trl# #t/blk + ( to) trl# ( fr) endof
( default ...) trl# #t/blk + ( to) trl# ( fr)
endcase
?do
( set pointer called array based on unit# chosen ...)
i equ trl# get_unit_data
( is this a good trial? ...)
test_for_good_trial?
bad_trial? not
if ( yes, good trial)
( add in time for this trial ...)
pcs_time toneon + equ pcs_time
( initialize ...)
0 equ start_range
toneon equ end_range
0 equ bin#
\
\
end_range start_range
?do
( find start of cluster or end of pcs period ...)
begin
bin# end_range u<
array bin# + c@ 0= and
while
bin# 1+ equ bin#
repeat
( if cluster is found then update cluster counter and find end of cluster ...)
array bin# + c@ 0<>
if
( update cluster counter ...)
end_of_first_cluster_in_block 0<>
if #clusters 1+ equ #clusters then ( NOTE: wrong count)
( find end of cluster or end of pcs period ...)
begin
bin# end_range u<
array bin# + c@ 0<> and
while
( do not count first cluster ...)
end_of_first_cluster_in_block 0<>
if #spikes array bin# + c@ + equ #spikes then
( update bin# counter ...)
bin# 1+ equ bin#
repeat
( determine if this is the first or the latest cluster found ...)
end_of_first_cluster_in_block 0=
if
bin# equ end_of_first_cluster_in_block
trl# equ trial_of_first_cluster_in_block ( debugging)
else
bin# equ end_of_last_cluster_in_block
trl# equ trial_of_last_cluster_in_block ( debugging)
then
then
bin# i - ( adjust loop counter)
+loop
then
loop
2 #clusters u<=
if ( yes, more than one cluster found; therefore, can correctly compute Hz)
( correct for finding first cluster ...)
pcs_time end_of_first_cluster_in_block - equ pcs_time
( correct for finding last cluster ...)
pcs_time toneon end_of_last_cluster_in_block - - ( <--two minus signs) equ pcs_time
( correct for total number of clusters ...)
#clusters 1- equ #clusters ( NOTE: wrong count)
( calculate hz ...)
pcs_time #spikes 10 * 10000 um* rot bin * ( denominator)
dup >r um/mod ( remainder quotient)
swap 2* r> ( quotient remainder*2 denominator) / + ( answer)
analysis case
0 of ( session analysis hz)
unit#
case
1 of equ unit1_PCS_Hz endof
2 of equ unit2_PCS_Hz endof
3 of equ unit3_PCS_Hz endof
4 of equ unit4_PCS_Hz endof
drop ( default)
endcase
endof
1 of ( block analysis hz) equ pcs_hz endof
( default ...) drop
endcase
then
noop ;
: PCS_session_analysis ( --) 0 equ analysis PCS_block|session_analysis ;
: PCS_block_analysis ( --) 1 equ analysis PCS_block|session_analysis ;
: cluster ( --) ( working_definition ) ( unit# must be set by user)
( cluster used to be called xxx when I was debugging the program)
printing if printer +condensed then
selectfile
PCS_session_analysis
( header ...)
" Unit analysis for file = " count type filename makelc count type cr
" Data information type is" count type ( information u. )
information case
1 of " intracluster interval in bins (ici_info) " count type endof
2 of " duration in bins (duration_info) " count type endof
3 of " spikes as counts (spike_info) " count type endof
4 of " time in msec (time_info) " count type endof
5 of " raw bin# (bin_info = raw_info = start_info) " count type endof
6 of " latency in msec (latency_info)" count type endof
7 of " frequency in Hertz (hz_info = frequency_info = freq_info)" count type endof
8 of " latency (msec),frequency (Hz) ( special_info)" count type endof
9 of " test ( test_info)" count type endof
" information chosen is out of range" count type abort ( default)
endcase cr
" Unit criterion = " count type unit_Hz_criterion u. " times" count type
session case
true of " session" endof
false of " block" endof
endcase count type
" baseline." count type cr
" Bad trial criterion = " count type bad_units u. " counts in baseline." count type cr
" Analysis by " count type
session case
true of " session" count type endof
false of " block" count type endof
endcase
cr cr
" unit number " count type unit# u. cr
" Trial_number#
PCS / CS // UCS clusters " count type cr
( zero variables ...)
0 equ total_PCS_spikes_in_block
0 equ total_PCS_spikes_in_session
0 equ total_good_trials
( for every trial ...)
#trls ( to) 0 ( fr)
?do
( analyze pcs for good trials and calculate pcs hz ...)
i 1+ #t/blk mod 1 = ( first trial of the block?)
if i 1+ equ trl# PCS_block_analysis then
( set data pointer ...)
i 1+ equ trl# get_unit_data
( print trial type for every trial ...)
trl# 1- trialtypetable 1+ + c@
case
ascii 1 of ascii T emit endof
ascii 2 of ascii P emit endof
ascii 3 of ascii A emit endof
endcase
space
( analyze every trial ...)
trl# s>d 4 d.r ascii # emit space ( print every trial number)
is_this_a_good_trial? ( count PCS spikes and make sure it is a good trial)
bad_trial? not if find_and_print_clusters then
bad_trial? not if PCS_Hz_in_this_trial then
( print block information ...)
print_block
( had enough? abort analysis ...)
nuf? if leave then
loop
( print session totals ...)
cr " Total PCS spikes = " count type total_PCS_spikes_in_session u.
cr " Total good trials = " count type total_good_trials u.
cr " Session PCS frequency = " count type
unit# case
1 of unit1_PCS_Hz endof
2 of unit2_PCS_Hz endof
3 of unit3_PCS_Hz endof
4 of unit4_PCS_Hz endof
endcase
.hz
printing if page console then ;
cr
cr .( Specify unit for analysis -- e.g., unit1, unit2 ...)
cr .( Specify parameters -- e.g., bob, xty, claire_tones ...)
cr .( Specify computations -- e.g., special_info, hz_info, latency_info, spike_info, bin_info ...)
cr .( Specify criterion level -- e.g., 3 equ unit_Hz_criterion )
cr .( Specify bad trial criterion -- e.g., 100 equ bad_units )
cr .( Specify type of analysis -- e.g., by_block or by_session)
cr .( Set printer -- e.g., +printer, -printer, true equ printing, false equ printing)
cr .( Start analysis with cluster<return>)
cr
cr .( Examples: unit2 bob hz_info 2 equ unit_Hz_criterion -printer cluster<return>)
cr .(
latency_info cluster<return>)
cr .(
unit1 +printer cluster<return> ... )
cr
( stop)
(
the following words were created to compare two different ways of calculating the)
( frequency.)
(
test_calc_hz is based on calculate_hz, found in dave.txt file, is used in cluster.txt to)
( calculate the frequency of individual clusters in each trial. frequency is rounded)
( and calculated to 1 Hz.)
(
test_freq is based on freq, found in cluster.txt, and used in cluster.txt to calculate i. pcs)
( frequency for each trial and ii. pcs frequency for each block of trials. frequency is rounded )
( and calculated to 0.01 Hz.)
(
here test_calc_hz is scaled by multiplying it by 100 to make comparisons with test_freq.)
(
a test was made using 200 10 test<return> has been tested.)
(
the results show that there is surprisingly good agreement. that is, test_calc_hz -- which)
( has less precision -- seems to be a correctly rounded version of test_freq.)
( : test_calc_hz )
( stack: time count --)
( equ spikes_in_cluster)
( equ cluster_duration)
( 0 equ ici)
( calculate_Hz )
( 100 * )
( .hz ;)
( : test_freq )
( stack: time count --)
( comment: calculate & print hz)
( 10 * 10000 um* rot bin * )
( stack: denominator)
( dup >r um/mod )
( stack: remainder quotient)
( swap 2* r> )
( stack: quotient remainder*2 denominator)
(/+)
( .hz ;)
( : test )
( stack: time count --)
( 2dup test_calc_hz 5 spaces test_freq cr ;)
( end)
Download