Unit Generator

1 view
Skip to first unread message

Macedonio Heninger

unread,
Aug 3, 2024, 3:59:28 PM8/3/24
to wardroventee

Unit generators (or ugens) are the basic formal units in many MUSIC-N-style computer music programming languages. They are sometimes called opcodes (particularly in Csound), though this expression is not accurate in that these are not machine-level instructions.

Unit generators form the building blocks for designing synthesis and signal processing algorithms in software. For example, a simple unit generator called OSC could generate a sinusoidal waveform of a specific frequency (given as an input or argument to the function or class that represents the unit generator). ENV could be a unit generator that delineates a breakpoint function. Thus ENV could be used to drive the amplitude envelope of the oscillator OSC through the equation OSC*ENV. Unit generators often use predefined arrays of values for their functions (which are filled with waveforms or other shapes by calling a specific generator function).

I have developed a code-generator that takes our python interface to our C++ code (generated via SWIG) and generates code needed to expose this as WebServices. When I developed this code I did it using TDD, but I've found my tests to be brittle as hell. Because each test essentially wanted to verify that for a given bit of input code (which happens to be a C++ header) I'd get a given bit of outputted code I wrote a small engine that reads test definitions from XML input files and generates test cases from these expectations.

So I'm trying to think of alternative approaches to this problem, and it strikes me I'm perhaps tackling it the wrong way. Maybe I need to focus more on the outcome, IE: does the code I generate actually run and do what I want it to, rather than, does the code look the way I want it to.

I started writing up a summary of my experience with my own code generator, then went back and re-read your question and found you had already touched upon the same issues yourself, focus on the execution results instead of the code layout/look.

Recall that "unit testing" is only one kind of testing. You should be able to unit test the internal pieces of your code generator. What you're really looking at here is system level testing (a.k.a. regression testing). It's not just semantics... there are different mindsets, approaches, expectations, etc. It's certainly more work, but you probably need to bite the bullet and set up an end-to-end regression test suite: fixed C++ files -> SWIG interfaces -> python modules -> known output. You really want to check the known input (fixed C++ code) against expected output (what comes out of the final Python program). Checking the code generator results directly would be like diffing object files...

If you are running on *nux you might consider dumping the unittest framework in favor of a bash script or makefile. on windows you might consider building a shell app/function that runs the generator and then uses the code (as another process) and unittest that.

A third option would be to generate the code and then build an app from it that includes nothing but a unittest. Again you would need a shell script or whatnot to run this for each input. As to how to encode the expected behavior, it occurs to me that it could be done in much the same way as you would for the C++ code just using the generated interface rather than the C++ one.

Provided you have your generated code assembled from smaller chunks, and the chunks do not change frequently, you can exercise more conditions and test a little better, and hopefully avoid having all your tests break when you change specifics of one chunk.

So in conclusion, a single unit / specification can have multiple behaviours, and the specification grows as you develop the unit / system; and if your system under test depends on other concrete systems within it, watch out.

My recommendation would be to figure out a set of known input-output results, such as some simpler cases that you already have in place, and unit test the code that is produced. It's entirely possible that as you change the generator that the exact string that is produced may be slightly different... but what you really care is whether it is interpreted in the same way. Thus, if you test the results as you would test that code if it were your feature, you will find out if it succeeds in the ways you want.

Basically, what you really want to know is whether your generator will produce what you expect without physically testing every possible combination (also: impossible). By ensuring that your generator is consistent in the ways you expect, you can feel better that the generator will succeed in ever-more-complex situations.

In this way, you can also build up a suite of regression tests (unit tests that need to keep working correctly). This will help you make sure that changes to your generator aren't breaking other forms of code. When you encounter a bug that your unit tests didn't catch, you may want to include it to prevent similar breakage.

In my case, the program generates many types of code (C#, HTML, SCSS, JS, etc.) that compile into a web application. The best way I've found to reduce regression bugs overall is to test the web application itself, not by testing the generator.

It can only mean that one or more of the parts has either a missing or bad trim, so the length is off by even as much as .001 or less. If you uncheck the merge by part number on your BOM, you can look at the Unit Qty fields, and you should see where one or more of the "Varies" parts has a slightly different length. I generally use Trim/Extend instead of Trim To Frame, but that shouldn't make much difference. What could happen, fairly easily, is an incorrect surface being selected by accident during the trim process... like to the ID of a tube or beam or whatever... just an example, without knowing what your frame looks like.

This isn't the only possible cause. I'm pretty certain there's some sort of Inventor bug that causes it was well. I have the precision turned all the way up and as you can see in the attached screen shots they do not vary at all yet the Inventor BOM says they do. This is extremely frustrating and has caused a lot of lost time.

I've had it happen. Seemed to be tied to frame generator components that had end treatments done to them-originally different files trimmed to be same length or with end treatments deleted. Inventor then handled them as different components (because to the software they would be) even though they look the same. My 2 cents anyway

Thing is, while doing the copy + change, a few of the x-braces didn't update correctly, so my Parts List was screwed up on some of the drawings ('VARIES' showing in the 'LENGTH' column). The most common cause of that was:

The other main reason was some of the parts differed in length even though they were exact duplicates (mirrored but identical). The reason is b/c FG refused to update them. So I had to delete them and recreate them and that solved the problem. What a PITA! You have to comb through the entire dataset to make sure you don't have other problems with FG members. PITA all the way baby! It's like I always say, when you create more data, you need more tools to manage that data, or you pile up the work exponentially, and nobody can get it done on time.

I am using a Parts List in an Inventor Drawing of an Inventor Assembly that contains parts with Base Unit 'Each' and Frame Generator members with Base Quantity 'm'. I set the Part Number in the BOM for all of the similar frame generator members to the same value so that they roll-up in the Structured BOM.

This works fine. The Parts List in the drawing displays the 'Each' components without a unit / decimal precision and the frame generator parts all get nicely summed up which is what I want. Unfortunately the decimal precision of the frame generator members is defaulting to 0.000 which is making my parts list untidy and I want to round this figure up to the nearest meter.

I have tried going into each frame member and changing the tolerance > precision on each and every member. This works to reduce the number of decimal places in the parts list once all of the members are changed but is incredibly tedious. It also doesn't quite fix my problem as I would like to round up and this approach rounds down.

I have also tried changing the column format of the parts list table or the QTY column to m and setting the decimal precision there using 'apply units formatting'. This works to fix the precision on the frame generator parts but unfortunately it also changes all of my normal 'each' parts too which is incorrect.

One thing that did look promising was introducing a substitution in the column format for the QTY column on the parts list table. I tried picking up the property 'G_L' which is a custom iProperty that the Frame Generator creates for all members that contains the length. My hope was to sum this field (which looks to be one of the options) and then be able to 'Apply Unit Formatting' of m with precision 0 for this sum. Unfortunately this doesn't seem to work as I expected and the parts list cell that it represents turns blue and has *Varies* in it. I've checked and all of the members have valid lengths in this G_L custom iProperty.

This is indeed doable. And, Column Substitution workflow will lead to desirable result. Please take a look at attached file. Open ExampleAssembly_fixed.idw. As you can see, the length has been rounded off. What I did was pretty simple.

But... my example wasn't a complete one (sorry). Please see attached a similar example, but this time the frame contains members of different lengths. All of the members are given the same part number so that they merge in the structured BOM. The BOM shows the correct total length. If we add the G_L substitution in the QTY column in the parts list that cell of the column now says *Varies*. Is there any way to get it to say the rounded total lengths?

The one you just attached did not work because there is a bit mismatch among G_L unit and properties. I end up opening each frame member, change document unit to meter, and change the Unit QTY so that they are in sync again. Once they are all set to meter unit, there is no need to substitute the values. It should just work. Please take a look at attached file.

c80f0f1006
Reply all
Reply to author
Forward
0 new messages