Loops within loops in PsychoPy Builder - builder

I am new to programming, and need some help with an experiment I'm constructing in PsychoPy builder. I have made something that works, but I can tell it's inelegant and there must be a better way.
I want to conduct 24 trials. Each trial will show 7 unique images, then 1 image which may or may not be from the 7, and users are then asked to enter y/n if they have seen the image before.
In my current code I have created 24 separate input files, each containing a list of the unique objects. I have created a loop which shows the seven objects in succession. I have then created separate routines for the pre-trial fixation screen (constant for all 24 trials) and the response (probe image and correct answer manually programmed). The code works, but it is very long, and if I wanted to change something in the fixation or the probe/response, I would need to change each of the 24 trials individually.
How can I instead get Builder to create a loop which contains the fixation screen (constant), the trial loop (picking the next seven unique objects (they are named sequentially from 1-168), and then a probe/response which is unique to each trial (I have these in an input file as follows. Probe refers to a number between 1 and 7 which references the position of the image in the sequence shown in the trial.)
TrialNumber Probe CorrAns
1 4 0
2 3 1
3 4 0
4 5 1
5 4 1
...
I hope my question makes sense and I would be grateful for any assistance.
Thanks PsychoPy Beginner.

Yes, you're correct that there is a (much) more efficient way to do this.
First, start with your conditions file (i.e. .csv or .xlsx). You only need one of them. It should have 24 rows (one per trial). It will need 8 columns: 7 to specify the unique images in a trial and an eighth to specify the repeated one.
Second, you need a loop to control the trials. This is connected to the conditions file, and encompasses all of the routines (the pre-trial fixation and the image routine.
Third, you need a second, inner loop, nested within the outer one. This encompasses only the image routine. i.e. the fixation routine will run 24 times (once per outer loop), and the image routine will run 7×24 times (i.e. 7 times per trial). The inner loop is not connected to a conditions file and is simply set to run 7 times.
So note that you no longer have 24 separate routines in Builder but only two (the fixation and image routines). Instead of duplicating routines, you repeat them via the loops.
In the image stimulus image field, you can construct the image name to use on each presentation. e.g. lets say the 8 columns in your conditions file are labelled 'image0', 'image1', etc. Then in the image field, put something like this:
$'image' + str(yourInnerLoopName.thisN)
i.e. on the first iteration within each trial, the image filename would come from column image0, the second from image1, and so on.
I don't know how you are handling the responses, but you will also probably need a ninth column in the conditions file that indicates what the correct response is. The keyboard component can access that to judge whether the response is correct or not.

Related

Looking for a more efficient way to pull data from multiple datasets in SAS

I'm trying to find a more efficient and speedier way (if possible) to pull subsets of observations that meet certain criteria from multiple hospital claims datasets in SAS. A simplified but common type of data pull would look like this:
data out.qualifying_patients;
set in.state1_2017
in.state1_2018
in.state1_2019
in.state1_2020
in.state2_2017
in.state2_2018
in.state2_2019
in.state2_2020;
array prcode{*} I10_PR1-I10_PR25;
do i=1 to 25;
if prcode{i} in ("0DTJ0ZZ","0DTJ4ZZ") then cohort=1;
end;
if cohort=1 then output;
run;
Now imagine that instead of 2 states and 4 years we have 18 states and 9 years -- each about 1GB in size. The code above works fine but it takes FOREVER to run on our non-optimized server setup. So I'm looking for alternate methods to perform the same task but hopefully at a faster clip.
I've tried including (KEEP=) or (DROP=) statements for each dataset included the SET statement to limit the variables being scanned, but this really didn't have much of an impact on speed -- and, for non-coding-related reasons, we pretty much need to pull all the variables.
I've also experimented a bit with hash tables but it's too much to store in memory so that didn't seem to solve the issue. This also isn't a MERGE issue which seems to be what hash tables excel at.
Any thoughts on other approaches that might help? Every data pull we do contains customized criteria for a given project, but we do these pulls a lot and it seems really inefficient to constantly be processing thru the same datasets over and over but not benefitting from that. Thanks for any help!
I happend to have a 1GB dataset on my compute, I tried several times, it takes SAS no more than 25 seconds to set the dataset 8 times. I think the set statement is too simple and basic to improve its efficient.
I think the issue may located at the do loop. Your program runs do loop 25 times for each record, may assigns to cohort more than once, which is not necessary. You can change it like:
do i=1 to 25 until(cohort=1);
if prcode{i} in ("0DTJ0ZZ","0DTJ4ZZ") then cohort=1;
end;
This can save a lot of do loops.
First, parallelization will help immensely here. Instead of running 1 job, 1 dataset after the next; run one job per state, or one job per year, or whatever makes sense for your dataset size and CPU count. (You don't want more than 1 job per CPU.). If your server has 32 cores, then you can easily run all the jobs you need here - 1 per state, say - and then after that's done, combine the results together.
Look up SAS MP Connect for one way to do multiprocessing, which basically uses rsubmits to submit code to your own machine. You can also do this by using xcmd to literally launch SAS sessions - add a parameter to the SAS program of state, then run 18 of them, have them output their results to a known location with state name or number, and then have your program collect them.
Second, you can optimize the DO loop more - in addition to the suggestions above, you may be able to optimize using pointers. SAS stores character array variables in memory in adjacent spots (assuming they all come from the same place) - see From Obscurity to Utility:
ADDR, PEEK, POKE as DATA Step Programming Tools from Paul Dorfman for more details here. On page 10, he shows the method I describe here; you PEEKC to get the concatenated values and then use INDEXW to find the thing you want.
data want;
set have;
array prcode{*} $8 I10_PR1-I10_PR25;
found = (^^ indexw (peekc (addr(prcode[1]), 200 ), '0DTJ0ZZ')) or
(^^ indexw (peekc (addr(prcode[1]), 200 ), '0DTJ4ZZ'))
;
run;
Something like that should work. It avoids the loop.
You also could, if you want to keep the loop, exit the loop once you run into an empty procedure code. Usually these things don't go all 25, at least in my experience - they're left-filled, so I10_PR1 is always filled, and then some of them - say, 5 or 10 of them - are filled, then I10_PR11 and on are empty; and if you hit an empty one, you're all done for that round. So not just leaving when you hit what you are looking for, but also leaving when you hit an empty, saves you a lot of processing time.
You probably should consider a hardware upgrade or find someone who can tune your server. This paper suggests tips to improve the processing of large datasets.
Your code is pretty straightforward. The only suggestion is to kill the loop as soon as the criteria is met to avoid wasting unnecessary resources.
do i=1 to 25;
if prcode{i} in ("0DTJ0ZZ","0DTJ4ZZ") then do;
output; * cohort criteria met so output the row;
leave; * exit the loop immediately;
end;
end;

R307 Fingerprint Sensor working with more then 1000 fingerprints

I want to integrate fingerprint sensor in my project. For the instance I have shortlisted R307, which has capacity of 1000 fingerprints.But as project requirement is more then 1000 prints,so I will going to store print inside the host.
The procedure I understand by reading the datasheet for achieving project requirements is :
I will register the fingerprint by "GenImg".
I will download the template by "upchr"
Now whenever a fingerprint come I will follow the step 1 and step 2.
Then start some sort of matching algorithm that will match the recently downloaded template file with
the template file stored in database.
So below are the points for which I want your thoughts
Is the procedure I have written above is correct and optimized ?
Is matching algorithm is straight forward like just comparing or it is some sort of tricky ? How can
I implement that.Please suggest if some sort of library already exist.
The sensor stores the image in 256 * 288 pixels and if I take this file to host
at maximum data rate it takes ~5(256 * 288*8/115200) seconds. which seems very
large.
Thanks
Abhishek
PS: I just mentioned "HOST" from which I going to connect sensor, it can be Arduino/Pi or any other compute device depends on how much computing require for this task, I will select.
You most probably figured it out yourself. But for anyone stumbling here in future.
You're correct for the most part.
You will take finger image (GenImg)
You will then generate a character file (Img2Tz) at BufferID: 1
You'll repeat the above 2 steps again, but this time store the character file in BufferID: 2
You're now supposed to generate a template file by combining those 2 character files (RegModel).
The device combines them for you, and stores the template in both the character buffers
As a last step; you need to store this template in your storage (Store)
For searching the finger: You'll take finger image once, generate a character file in BufferID : 1 and search the library (Search). This performs a linear search and returns the finger id along with confidence score.
There's also another method (GR_Identify); does all of the above automatically.
The question about optimization isn't applicable here, you're using a 3rd party device and you have to follow the working instructions whether it's optimized or not.
The sensor stores the image in 256 * 288 pixels and if I take this file to host at maximum data rate it takes ~5(256 * 288*8/115200) seconds. which seems very large.
I don't really get what you mean by this, but the template file ( that you intend to upload to your host ) is 512 bytes, I don't think it should take much time.
If you want an overview of how this system is implemented; Adafruit's Library is a good reference.

Windows batch card game not working properly, don't know how to fix

So for our computer science class, we had to write a program that randomly generates cards, i decided to do mine in batch, because im a massive noob XD
I was confident that i could do it as im quite experienced with it. Even though batch isn't by any means a good 'language' if your going to call it that. I was able to fix most of the problems by myself with some hard work. I am however, still having some issues i don't know how to resolve.
My biggest issues i don't know how to fix are...
Text not being displayed properly.
Numbers (i use for the base of the AI and card generation) sometimes not being defined properly in variables.
The point system just refuses to work not matter what i do.
It sometimes randomly just flat out decides to crash on me if i skip a 'TIMEOUT' or a 'PAUSE'.
Some 'IF' statements not being executed properly even though there exactly the same as the other ones.
I'm sorry if this question is too broad, but i really didn't know quite how to summarize it.
Here is a link to my card game: http://pastebin.com/t2S3yWk5
Here is our question:
1) Create a program that will generate two random numbers - one that maps to a suit (hearts,diamonds, clubs or spades) and one that maps to a card (Ace, 2, 3, ..... Jack, Queen, King)
*Mine is slightly different, it generates two different suits based on two random numbers.*
2) Create a program that will generate a random card and then ask the user to go Higher,Lower or Quit. If the player chooses Higher the next card must be of a higher value or theplayer is out. Likewise for Lower.
3)Extending the previous program, the user will select a trump suit at the start of the game. If the card is a trump suit card then the game continues regardless of the card’s value. The program will keep score and will save the score to a highscore file. The user will also be able to display the current highscore file.
I would like to try and do this stuff (listed above) myself. I just need help trying to fix my existing program.
I hope that if your reading this you could give me some advise or provide solutions to some of my problems. Thanks in advance! :3
Good news; nothing is super wrong with your code, it's just a bunch of little things that seem like a lot. Some off-by-one errors and a missing variable that I can only assume got replicated from copying and pasting.
Text not being displayed properly
I assume this is the "Access denied" errors that your code produces instead of the AI's comments. This is due to the fact that > and < are used for output redirection, so the emoticons you are adding are trying to create a file in a place you don't have access to. Either get rid of them (recommended) or use ^ to escape them (^>:)).
Numbers (I use for the base of the AI and card generation) sometimes not being defined properly in variables
%random% %% 5 results in one of the numbers in the set 0, 1, 2, 3, 4. You currently do not have an if statement for what should happen if 0 is randomly selected. Add an if statement or have the code go back to the top of the section if a 0 is selected.
The point system just refuses to work no matter what I do
You're going to kick yourself...
Your set statements are missing the assignment portion. SET /A %p1p% + 2 should be SET /A p1p=%p1p% + 2 and so forth (or set /a p1p+=2 if you think that looks better).
If sometimes randomly just flat out decides to crash on me if I skip a 'TIMEOUT' or 'PAUSE'
I couldn't replicate that, but the code seemed to work fine when I removed those statements.
Some 'IF' statements not being executed properly even though they're exactly the same as the other ones
Your comment indicated lines 119-132, which include the if statements that assign points. See above for why those aren't working.
Some other recommendations for your code
Your variable names should be more descriptive. For example, ctog doesn't tell me anything about what that variable should be; I can look at the code to see what it does, but without any context, that could be doing anything.
You should add the /i flag to the if statements that check which card you put down so that C1 and c1 get treated the same. On a related note, you should add a check for when the player enters something other than C1 or C2. You can even use a choice command like you did earlier.
:pvic is missing an exit command, so you automatically play again if you win. Combined with the fact that you only check if lt is equal to 2, not greater than or equal to 2, there's no way to stop playing if you win. Also on the subject of end game conditions, there's no if statement for if you tie the computer.
cp1 and num1 are effectively the same variable, there's no reason to have both (same with cp2/num2, ap1/num3, and ap2/num4).
You need some kind of goto at the end of :pc1 so that :pc2 doesn't automatically run after :pc1 finishes.

Renaming redundant IDs sequentially

Not sure if there's an answer for this, but I'm in a situation where I have a set of idential elements, each having a sequential ID, like id="thiselement1", id="thiselement2", id="thiselement3" etc...
Is there a fast way for me to copy and paste one element 100 times and then give each a sequential identifier as shown above? Trying to save manually typing numbers over and over again.

UI for capturing a timespan or duration

What's a good web-based UI for capturing a time duration from the user.
Lets say that we want to capture a time duration in minutes.
But would like to present it such that the user can enter in hours and\or minutes.
Just use 2 textboxes for hrs\min?
Or a single textbox and let them type in "1hr 31min" or "91 min" ?
Or is there something better?
If you have two text boxes labelled hours and minutes then you need to deal with case where the user types into both of them.
3 into h and 35 into m => pretty clear. 3 hours 35 mins
nothing into h and 95 into m => 1 hour 35 mins (probably update the display to show that)
but what about
2 into h and then 95 into m => does that mean 3 h 35 or 1 hour 35
I've used too many annoying UIs where changing a field zaps other entries to be confident that I can devise an unastonishing set of behaviours.
Hence I would go for a single box into which we can type 3h or 1h 35m or 95m and have a separate read-only display of the interpretation.
There seems to be an opportunity for a nice widget to allow a mouse driven entry, in the same way as a calendar widget allows date entry. A little clock with dragable hands?
Thanks for all the feedback.
What I finally ended up doing was, having a single textbox that shows the time duration in the format "xxhrs yymin"
The user can edit it and when focus moves away from the textbox, it recalculates the duration and reformats the text into the canonical form.
The parser to interpret the text entered is fairly liberal.
It's a set of regular expressions to match any number followed by 'h' or 'm' or 'd' to represent hours, minutes and days.
If it doesn't find any 'unit' with a number in front of it, it assumes you have typed in a pure number as minutes and will interpret it as such.
So if the user types:
"1.5h", it will reformat to "1hr 30min" upon leaving the textbox.
"90 min" will also be reformatted as "1hr 30min"
The parser only looks at the first character following the number, which means you can enter "1 day, 7 hours and 19 minutes" and it will recognize it correctly.
Of course, it would also recognize "2 holes and 19 mice" as "2hrs and 19min".
I think I can live with that.
Just let them type the numbers only in a pre defined time format.
Place 2 textboxes for hour and minute without the hr or min.
Also you have to define whether it is a 24 hour system or 12 hour.
Well, separate hours and minutes fields is the safest but slower to use than a single field. You can default the hours to 0 if you don’t expect many durations over 1 hour.
Maybe it depends on your population, but I expect users will be able to handle hours and minutes in the same text box if you provide a prompt, such as “Time duration (hrs:min):”
With that prompt, accept any initial unbroken string of numbers as the hours and any subsequent unbroken string of numbers as minutes, so that all of the following input are treated as equivalent.
2:30
02:30
02:30:05
2.30 (or maybe not: while great for keypad entry, but you may want to make an exception for the decimal point to allow the user to enter fractional hours, such as 2.75 for 2 hrs 45 min.)
2 30
2 hrs 30 min
2 hours, 30 minutes
2jaQp 30!!!!
I see no reason to require that the minutes be less than 60. The user should also be able to express the time as:
:150
When the focus leaves the field, auto-correct whatever the users enter to the specified (hrs:min) format to feedback the interpretation you made.
If all you need for your purpose is a rough approximation of time (or your users are only estimating anyway), then consider option buttons or a dropdown list with ranges of duration (e.g., 0 to 5 minutes, 5 to 15 minutes, 15 min to 1 hour, Over an hour.). Or if there are definite bounds on the durations and the intervals are functionally linear, you can use a labeled slider.
Whatever input format or control you use, it should be compatible with the source of information. Where do users get this duration? What units, format, intervals, and degree of precision are used there? How do users think and talk about the time among themselves?
I think there should be no client side correction for the minutes greater than 60 as somebody suggested. It would only be confusing and generate unnecessary problems.
User entered the data so he should understand what he typed and there is no need to correct him.
I would leave these fields as filled by user. On the server side I would just calculate total minutes as:
$total_minutes = 60 * $_POST['hours'] + $_POST['minutes'];
I was just thinking about this and realized one familiar UI for this sort of thing is a microwave oven. For iPhone-like uses, a keypad may be better than the rolling scroller thing I often see.
In my case I think I'm going to go with a text field for "number" and a selectbox for "unit" (years, months, weeks, days, hours).
Sliders (jqueryui, html5) could be an option too, depending on what kind of range you're talking about.

Resources