I have two events with the same sampling event #sim:
unit monitor_a_u is {
sample_a : interface_port of tlm_analysis of data_item_s is instance;
data_a : simple_port of uint(bits:32) is instance;
keep data_a.hdl_path() == "<data_a's path>";
event signal_a_r is rise(signal_a$) #sim;
on signal_a_r {
var data_a : data_item_s = new;
data_a = data_a$;
sample_a$.write(data_a);
};
unit monitor_b_u is {
sample_b : interface_port of tlm_analysis of data_item_s is instance;
data_b : simple_port of uint(bits:32) is instance;
keep data_b.hdl_path() == "<data_b's path>";
event signal_b_f is fall(signal_b$) #sim;
on signal_b_f {
var data_b : data_item_s = new;
data_b = data_b$;
sample_b$.write(data_b);
};
When the two events above are triggered, data are sampled and compared by a scoreboard:
unit my_scbd_u like uvm_scoreboard {
scbd_port sample_a : add data_item_s;
scbd_port sample_b : match data_item_s;
sample_a_predict(item: data_item_s) is only {
add_to_scbd(item);
set_match_port(item, sample_b);
};
};
extend my_top_env {
my_scbd : my_scbd_u is instance;
mon_a : monitor_a_u is instance;
mon_b : monitor_b_u is instance;
connect_ports() is also {
mon_a.sample_a.connect(my_scbd.sample_a);
mon_b.sample_b.connect(my_scbd.sample_b);
};
};
Now in the simulator (IES ver. 15), the data I'd like to sample is at the vertical cursor in the waveform below, and the values are shown under the 'Values' column:
__
signal_a __________| |____________
__________ _______________
data_a ____0x1___X____0x0________
_____
signal_b _________| |___________
_______________ ___________
data_b _____0xA_______X___0xB_____
A data mismatch is detected at the time when signal_b falls, and the displayed message is something like: "data_b (0xA) is not equal to data_a (0x0)". I'm expecting the error report to be "data_b (**0xB**) is not equal to data_a (0x0)".
Can someone explain why the scoreboard seems to get data differently from what is seen on the waveform? Could this be a delta delay issue in Specman?
The Scoreboard itself does not sample the lines, it just adds the values that were passed to it via the ports. I guess that when port_b was written, the scoreboard got its current value (which was A at that time). When the value was compared, when port_a was written - the scoreboard compared against the stored value (A), and not the new value.
Do I see correct - The value A (the "add") is updated before the B (the "match")? If so, I assume you are using the delay_match_in_scbd() instead of match_in_scbd(). This means that the Scoreboard stores the value, and the compare take place when add() is called.
You can issue the command "trace scoreboard" to see when items are written to the scoreboard ports, and when compare takes place.
Related
There are two simple problems here in initializing this structure.
One is the enunumerated value TS (I get error : Cannot convert value of type 'TournNames' to expected argument type 'TournamentName')
the other is initializing an array of strings (I get the error : Cannot convert value of type '[String]' to expected argument type 'TouramentScores'
Suppose I am trying to set up a structure to model the scores of tennis players and all of their matches in each of the major tournaments (just for fun). Each tournament has a name (e.g. Wimbledon) and a series of scores for that player (for example, in the opening match, their score might be "4-6, 6-4, 7-6, 6-2")... upto 7 matches in each tournament. Each player should have an array of four tournaments (names and array of scores), and eventually there should be an array of players. I am also trying to use enums not too successfully. Ideally, if I want to find how Roger Federer did in his third match of wimbledon this year, I would access something like player.tournament.wim.Roundof32 or something roughly like that. But before I can even get to playing with that, I can't seem to init dummy data for even a single tournament.
Any ideas? I don't think this is that hard of question but I just don't know each. See "*** this line" below for two lines that are problematic
// tournament name enum
enum TournNames : String {
case wim = "Wimbledom"
case fo = "French Open"
case ao = "Australian Open"
case uo = "US Open"
}
//
struct TournamentName {
var Tname : TournNames // = .wim
}
// This is the structure for a tournament score array with some dummy values.
struct TouramentScores {
var Match1 : String = "7-6, 6-4, 3-6, 7-6"
var Match2 : String = "7-6, 6-4, 3-6, 7-6"
}
// This is one entire Tournament record for one player = tournament name + array of scores ... the next goal but not used here until I get over these hurdles
struct TournamentResult {
var TournamentName : TournNames = .wim
var Scores : TouramentScores
}
// ... finally the structure of a player ...
struct DummyTennisPlayer {
var LastName : String // last name
var FirstName : String //first name
var TN : TournamentName
var TS : TouramentScores
// var WimRes : TournamentResult // to start a single tournament
// var SeasonResults : [TournamentResult] // ultimately should be an array of 4 tournaments
}
// trying to initialize some dummy data without success after trying several things
extension DummyTennisPlayer {
static var dummyResults : [DummyTennisPlayer] {
[
DummyTennisPlayer.init(
LastName : "Federer",
FirstName: "Roger",
TN : TournNames.wim // **** this line
,
TS : ["XX", "yy"] /// *** this line
)
]
}
}
As I think you're discovering, a simple series of nested types is unlikely to cut it here. As soon as you get to entities like players, tournaments, matches and lookups like "how Roger Federer did in his third match of wimbledon this year", you've become a candidate for using a database where you can manipulate one-to-many and many-to-many relationships. I can't tell you what database to use, and anyway that's a matter of opinion; from what you've said so far, SQLite would be sufficient (and I am personally not a fan of Core Data just for this kind of thing).
I guess your code is a kind of exercise, so before you go on later to Core Data or SQLite,
extension DummyTennisPlayer {
static var dummyResults: [DummyTennisPlayer] = [
DummyTennisPlayer(LastName: "Federer", FirstName: "Roger", WimbledomResult: TournamentResult(Scores: TouramentScores()))
]
}
should answer your question.
1 - To initialize a Swift struct, use the following syntax:
MyStruct(property1: "my property1 value", property2: "my property2 value")
2 - the tournament name property in TournamentResult is already set to .wim so you just need to initialize the Scores. As your TournamentScores properties are already all set, you just need to pass an instance of TournamentScores() to TournamentResult(Scores:).
By the way, only use lowercases for the first letter of the name of your variables or struct properties: var lastName or TournamentResult(scores:).
I think you are confusing the term "multi-dimensional (array) structures" (which are just arrays nested inside other arrays, like that: [ [1, 2, 3], [2, 3, 4], [3, 4, 5]]) with the struct objects. You are probably not supposed to use structs so extensively here.
Don't hesitate to review the way you decide to use enums, structs, or arrays. Your code may work but will be difficult to read and use (example: how would you access a specific set score if you put all of the set scores in a single String? Why not use an array?)
This carries on my last question struggling with value assignment to optional class variable, for which David provided me a good hint to a similar problem.
After numerous iterations I now came up with a different approach, however, it still fails and I have no idea why (and basically what happens)
I have the class definitions
struct HighScores: Codable {
var Scores:Int
var highscoreRecord: [HighscoreRecord]
}
struct HighscoreRecord: Codable {
var Rank:Int
var Date:String?
var avDuration:Float?
var Score:Int?
var Tries:Int?
}
In the view controller I have declared a variable of type HighScores, which may read the data from a JSON file or which may be initialized when setting the first high score.
class GameplayViewController: UIViewController {
var jsonResult: HighScores?
...
if firstHighscore == 1 {
jsonResult?.Scores = 1
jsonResult?.highscoreRecord.append(HighscoreRecord(Rank: 1, Date: formatter.string(from: dateStart), avDuration: Float(lblSpeed.text ?? "0.0"), Score: Int(lblRatio.text ?? "0"), Tries: hits + misses))
...
print(jsonResult)
This compiles and also runs. However, if I monitor the jsonResult variable, it still shows nil after assigning the Scores and and highscoreRecord values.
What happens, why can I assign a value without an error and without actually assigning it?
And first and foremost, how do I get my values into jsonResult?
Cheers
So following on from the comments above if you changed the code to be something along the lines of this you create the instance of the struct and add the values.
var jsonResult: HighScores?
if firstHighscore == 1 {
jsonResult = HighScores(Scores: 1, highscoreRecord: [HighscoreRecord(Rank: 1, Date: "your date", avDuration: 0.0, Score: 0, Tries: 0)])
}
once created you can add more highscorerecords to the array as needed, using the append method.
I'm setting up a fairly complex Google sheet and trying to automate some routine interpolation with a script. I now have a script that works, but I want to optimise it.
Let me briefly describe the set up with some (simple) example data:
A B C D E
1 Lookup date Result Recorded date Value
2 17/8/2018 - 31/12/2018 210
3 31/12/2018 210 31/3/2019 273
4 14/2/2019 241.5 12/6/2019 411
5 31/3/2019 273
6 12/6/2019 411
7 1/7/2019 411
In this example, I have a small number of recorded values (columns D and E) and I want to compute the value for any date (column A). Column B is the output of the script. The problem is that my script is very slow, taking quite a while on my laptop (sometimes I must refresh the page), and never fully executing on my iPad.
I think part of this may be the volume of requests: I run this script for about 200 cells in my sheet.
I will briefly explain the script (full javascript code below).
It creates a custom function getvalue(x, y, lookupdate) which, for a given x-range (col. D) y-range (col. E) and "lookup date" (eg A4) will return the correct result (eg B4). This result is either:
blank if the lookup date occurs before the first recorded date
the exact value if the lookup date equals a recorded date
an interpolated value if the lookup date is in between two recorded dates
the final recorded value if the lookup date is beyond the range of the recorded dates
Now I have optimised this somewhat. In my implementation, I actually run it as an array for 100 cells in column A (only some of which actually need to run the script). I have another simple system that basically auto-populates the date in column A as a binary flag to say the script needs to run. So using ISBLANK() as a switch, my array formula for cells B3:B103 is:
=ArrayFormula(IF(ISBLANK(A3:A103),"",getvalue(D:D,E:E,A3:A103)))
Even though the array covers 100 cells, only about 50 of them are "activated" with a date in the A column, so only about 50 of them actually need to run the getvalue function. However, as a final complication, I am actually doing this to calculate four different values for each "lookup date", running four different arrays in four columns, so that's what I say the script runs approx. 200 times.
Here is my actual script:
function getvalue(x, y, lookupdate) {
/// LOOKUP AN ARRAY
if (lookupdate.map) {
return lookupdate.map(function(v) {
return getvalue(x, y, v);
});
}
/// GET RID OF EMPTY CELLS IN COLUMN
var xf = x.filter(function(el) {
return el != "";
});
var yf = y.filter(function(el) {
return el != "";
});
/// GET RID OF HEADER ROW
xf.shift()
yf.shift()
/// SAVE THE FIRST AND LAST VALUES
var firstx = xf[0][0]
var firsty = yf[0][0]
var lastx = xf[xf.length - 1][0]
var lasty = yf[yf.length - 1][0]
/// FIGURE OUT WHAT TO RETURN
if (lookupdate < firstx) {
return "";
} else if (lookupdate.valueOf() == firstx.valueOf()) {
return firsty;
} else if (lookupdate > lastx) {
return lasty;
} else {
var check = 0, index;
for(var i = 0, iLen = xf.length; i < iLen; i++) {
if(xf[i][0] == lookupdate) {
return yf[i][0];
} else {
if(xf[i][0] < lookupdate && ((xf[i][0] - check) < (lookupdate - check))) {
check = xf[i][0];
index = i;
}
}
}
var xValue, yValue, xDiff, yDiff, xInt;
yValue = yf[index][0];
xDiff = xf[index+1][0] - check;
yDiff = yf[index+1][0] - yValue;
xInt = lookupdate - check;
return (xInt * (yDiff / xDiff)) + yValue;
}
}
The error message on the iPad is simply the cells never move past "Loading...", and on the laptop it takes much longer than expected.
The most confusing thing is that I think it has gotten worse since I set it up as an array. I previously had it where all 400 cells would run the ISBLANK() check, and then for the approx 200 triggered cells, they would individually run the script. This at least would load on the iPad.
I read on here and on general Google support that scripts will run a lot faster if you batch operations, but it seems to have gotten slower since moving from 200 single cells to 4 arrays.
Does this need to be optimised further, or is there some other reason it might be stalling on my iPad?
Is it even possible to optimise it down and do this in a single call, instead of in 4 arrays?
Accounting for the case
else if (lookupdate.valueOf() == firstx.valueOf()) return firsty;
is superfluous because it is covered already by if(xf[i][0] == lookupdate)
(xf[i][0] - check) < (lookupdate - check) can be simplified to xf[i][0] < lookupdate
You are using pure javascript code, but keep in mind that App Script has many additional functions which are handy when working with Spreadsheet.
https://developers.google.com/apps-script/reference/spreadsheet/
So, e.g. for running your function only for the populated range functions like getDataRange() or getRange() in combination with getNextDataCell() and getLastRow() will be very useful for you.
The main important point - the functionality of your script. Are you assuming that there is an approximately linear relationship between Recorded date and value, and thus interpolate the value for not recorded dates?
In this case the statistically most precise way (and the programmatically simplest one) would be to calculate your slope between the first and last x and y respectively. That is:
Result=first_y+((y_last-y_first)/(x_last-x_first)*(Lookup_Date-first_x))
If this approach is suitable for you, your code would simplify and would look in App Script something like:
function myFunction() {
var ss=SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var Result_Range=ss.getRange("A2:B")
var limit=Result_Range.getNextDataCell(SpreadsheetApp.Direction.DOWN).getLastRow()
var Result_values=Result_Range.getValues();
var valueRange=ss.getRange("D1:E");
var values=valueRange.getValues();
var last_Index=valueRange.getNextDataCell(SpreadsheetApp.Direction.DOWN).getLastRow()
var last_y=values[last_Index-1][1];
var last_x=values[last_Index-1][0].valueOf();
var first_y=values[1][1];
var first_x=values[1][0].valueOf();
var slope=(last_y-first_y)/(last_x-first_x);
for(var i=1;i<limit;i++)
{
Result_Range.getCell(i,2).setValue(first_y+(slope*(Result_values[i-1][0].valueOf()-first_x)))
Logger.log(i)
Logger.log(Result_values[i][0].valueOf()-first_x)
}
}
I want to find pattern of events that follow
Inner pattern is:
Have the same value for key "sensorArea".
Have different value for key "customerId".
Are within 5 seconds from each other.
And this pattern needs to
Emit "alert" only if previous happens 3 or more times.
I wrote something but I know for sure it is not complete.
Two Questions
I need to access the previous event fields when I'm in the "next" pattern, how can I do that without using the ctx command because it is heavy..
My code brings weird result - this is my input
and my output is
3> {first=[Customer[timestamp=50,customerId=111,toAdd=2,sensorData=33]], second=[Customer[timestamp=100,customerId=222,toAdd=2,sensorData=33], Customer[timestamp=600,customerId=333,toAdd=2,sensorData=33]]}
even though my desired output should be all first six events (users 111/222 and sensor are 33 and then 44 and then 55
Pattern<Customer, ?> sameUserDifferentSensor = Pattern.<Customer>begin("first", skipStrategy)
.followedBy("second").where(new IterativeCondition<Customer>() {
#Override
public boolean filter(Customer currCustomerEvent, Context<Customer> ctx) throws Exception {
List<Customer> firstPatternEvents = Lists.newArrayList(ctx.getEventsForPattern("first"));
int i = firstPatternEvents.size();
int currSensorData = currCustomerEvent.getSensorData();
int prevSensorData = firstPatternEvents.get(i-1).getSensorData();
int currCustomerId = currCustomerEvent.getCustomerId();
int prevCustomerId = firstPatternEvents.get(i-1).getCustomerId();
return currSensorData==prevSensorData && currCustomerId!=prevCustomerId;
}
})
.within(Time.seconds(5))
.timesOrMore(3);
PatternStream<Customer> sameUserDifferentSensorPatternStream = CEP.pattern(customerStream, sameUserDifferentSensor);
DataStream<String> alerts1 = sameUserDifferentSensorPatternStream.select((PatternSelectFunction<Customer, String>) Object::toString);
You will have an easier time if you first key the stream by the sensorArea. They you will be pattern matching on streams where all of the events are for a single sensorArea, which will make the pattern easier to express, and the matching more efficient.
You can't avoid using an iterative condition and the ctx, but it should be less expensive after keying the stream.
Also, your code example doesn't match the text description. The text says "within 5 seconds" and "3 or more times", while the code has within(Time.seconds(2)) and timesOrMore(2).
Just to give you a little background on my question:
I am creating a form in Google App Script using the UI Services and I am storing specific calendar events in a dataArray. So the event object is stored in the array. I want to pass this array to the submit function but can't figure out how to go about this because :
I can't add it as a callback element (because it isn't a widget)
I can't store the event object in a widget (i.e. a listbox, etc) and then add that widget as a callback element.
Here is a brief sample of what I am trying to do:
var cal= CalendarApp.getDefaultCalendar();
var event= cal.getEvents(new Date("June 16, 2013 PST"),
new Date("July 22, 2013 PST"));
var specific = new Array;
for( var j=0; j<event.length;j++){
specific.push(event[j]);
//This stores the events in the specific variable
//I want to send this variable (w/ the data) to another function on submit
I would appreciate any suggestions you can lend me.
Thanks!
As a complement to the answer I gave in the comments : "you could also simply store the id and while you read the events again using the same start/end time you can check if an event correspond to the saved ID in a loop... if a match is found with the right ID you are sure it's the right event"
Here is a piece of code I use to modify/update/delete calendar events using their ID as reference. This code is used to delete specific events selected from the spreadsheet, the code to modify events is roughly the same, at least it uses the same ID checking.
...
var cal = CalendarApp.openByName(calName);
if (cal) {
var events = cal.getEvents(new Date(date_deb), new Date(date_fin),{max: 4000}); // stocke tt ds une variable array
var sel= sh.getRange(6,1,sh.getLastRow()-5, 10).getValues();// read data in the SS
for(e=0;e<events.length;++e){
var delFlag = false;
var ID = events[e].getId();
for(n=0;n<sel.length;++n){
if ((sel[n][8] == "x"||sel[n][8] == "X")&&sel[n][9]==ID){ // the ID here is stored in the spreadsheet in column J and I use a 'X' marker to select which event should be deleted
delFlag = true;
sh.getRange(n+6,9,1,2).setBackgroundColor('#ff5500');
SpreadsheetApp.flush();
Logger.log('FLAG '+ e);
break;
}
}
if(delFlag){
try{
var toDelete = events[e].deleteEvent();
++todel;
delFlag = false;
Logger.log('event deleted : '+sel[n][1]);
}catch(Err){Logger.log('Event from a serie already deleted from another occurence')}
}
}
}
var msg = todel + " événement(s) effacé(s) dans l'Agenda '"+calName+"'";
ss.toast("Effacement terminé", msg, 3);
...