CHDK Forum

CHDK Development => General Discussion and Assistance => Topic started by: waterwingz on 10 / August / 2013, 12:12:54

Title: 1.3 development proposal - exposure conversion functions
Post by: waterwingz on 10 / August / 2013, 12:12:54
As I work through lapser's patch file for his shot_histogram_request mods and remove things not related to that,  I stumbled on his "real world to APEX96" functions.

Code: [Select]
+    FUNC(shutter_to_tv96)
+    FUNC(tv96_to_shutter)
+    FUNC(iso_to_sv96)
+    FUNC(sv96_to_iso)
+    FUNC(aperture_to_av96)
+    FUNC(av96_to_aperture)
They are not really part of the shot_histogram & continuous shooting exposure adjust code so I guess I'll strip them out too.   

But is "somebody" going to add the equivalent as part of 1.3.0 (or as part of the real vs market ISO conversion) ?

I can do it but I'm assuming it needs to be tied to the fixes for ISO in 1.3.0?

UPDATE :  patch file of lapser's apex96 Lua conversion functions attached
 
Title: Re: Re: 1.3 development planning thread
Post by: philmoz on 10 / August / 2013, 20:55:13
As I work through lapser's patch file for his shot_histogram_request mods and remove things not related to that,  I stumbled on his "real world to APEX96" functions.

Code: [Select]
+    FUNC(shutter_to_tv96)
+    FUNC(tv96_to_shutter)
+    FUNC(iso_to_sv96)
+    FUNC(sv96_to_iso)
+    FUNC(aperture_to_av96)
+    FUNC(av96_to_aperture)
They are not really part of the shot_histogram & continuous shooting exposure adjust code so I guess I'll strip them out too.   

But is "somebody" going to add the equivalent as part of 1.3.0 (or as part of the real vs market ISO conversion) ?

I can do it but I'm assuming it needs to be tied to the fixes for ISO in 1.3.0?

UPDATE :  patch file of lapser's apex96 Lua conversion functions attached

The ISO conversion is using the old CHDK equation for 'real' ISO. It needs to be updated to use the 1.3 conversion.

Not sure I see the need for the optional 'scale' parameter in all of the functions - the level of inaccuracy in the integer conversion means you're not going to get much better than using a default value of 1000.
This would also simplify the code.
Edit2: The other option here is to use the imath library fixed point type for shutter speed and aperture (instead of multiplying everything by 1000 / 'scale').

Personally I would also lose the convert96 function and move the conversion code into the calling functions.

Edit: I also don't like the way the 'shutter_to_tv96' treats negative numbers as a special case so that -2000 and 500 both mean 1/2 second shutter speed.

Phil.
Title: Re: Re: 1.3 development planning thread
Post by: reyalp on 10 / August / 2013, 22:10:54
Edit2: The other option here is to use the imath library fixed point type for shutter speed and aperture (instead of multiplying everything by 1000 / 'scale').
Possibly an imath based standard Lua module would be sufficient, and these don't need to go into the core at all?
Title: Re: Re: 1.3 development planning thread
Post by: waterwingz on 11 / August / 2013, 13:42:17
Edit2: The other option here is to use the imath library fixed point type for shutter speed and aperture (instead of multiplying everything by 1000 / 'scale').
Possibly an imath based standard Lua module would be sufficient, and these don't need to go into the core at all?
As long as we are okay with leaving the uBASIC user base farther and farther behind?

At some point,  I suppose we could just give the users a turing machine simulator and let them code from there  :haha

Seriously though,  it seems like these are pretty much core functionality for a package that is supposed to be about photography.   

I'm also in favor of a extending the @param pragma to allow user entry in ISO units,  Tv seconds, or Av f-stop numbers from the Script  menu,   returning the apex96 equivalent to the script itself. 
Title: Re: Re: 1.3 development planning thread
Post by: reyalp on 11 / August / 2013, 14:10:56
As long as we are okay with leaving the uBASIC user base farther and farther behind?
I'd be OK with that, though including it ubasic would be preferable.
Quote
Seriously though,  it seems like these are pretty much core functionality for a package that is supposed to be about photography.   
Agreed. I'm just saying if we can provide the equivalent functionality, a library may be an option. If the only difference from a user POV is they need require"explib" at the top of their script, that's not a good reason for putting it in C code. If using C code can provide better functionality, it's certainly worth doing in C.
Quote
I'm also in favor of a extending the @param pragma to allow user entry in ISO units,  Tv seconds, or Av f-stop numbers from the Script  menu,   returning the apex96 equivalent to the script itself.
This would be an excellent feature.
Title: Re: Re: 1.3 development planning thread
Post by: lapser on 16 / August / 2013, 12:18:39
I just found this discussion, so let me add my thoughts.

I wrote up some documentation and posted it in the Histogram Request thread. Here's the part on the Apex96 functions:
Quote
==========
*** Apex Conversion Functions ***
==========

tv96=shutter_to_tv96(shutter_time[,scale]) (default scale is 1000 for msec)
  shutter_time>0 means msec (if scale=1000 default)
    For microseconds, set scale=1000000
  shutter_time<0 means function uses 1/-shutter_time
  Example:
  @param t Shutter Max (sec)
  @default t 10
  @param u Shutter Min (1/sec)
  @default u 3200
  tvmax=shutter_to_tv96(-u*1000)
  tvmin=shutter_to_tv96(t*1000)
  Note: You could also do this with
    tvmax=shutter_to_tv96(-u,1)
    tvmin=shutter_to_tv96(t,1)

shutter=tv96_to_shutter(tv96,scale)  note: default scale=1000
  converts tv96 to shutter time in msec
  if tv96>0, you can use a scale of 1000000 for microseconds or...
    you can use -tv96 and print out 1/seconds instead of msec
  Example: This Lua function returns a string with the time
    function seconds(tv) -- tv96 to time string i.e. print(seconds(tv))
      pre=""
      if(tv>0)then
        tv=-tv
        pre="1/"
      end
      tv=tv96_to_shutter(tv) -- tv96 to msec
      ti=tv/1000 -- integer part
      ts=string.format("%s%u.%03u",pre,ti,tv%1000) -- xx.xxx or 1/xx.xxx
      if(ti>1)then -- truncate digits to reflect decimal precision
        if(ti>149)then ti=-5
        elseif(ti>14)then ti=-3
        else ti=-2 end
        ts=string.sub(ts,1,ti)
      end
      return ts
    end

sv96=iso_to_sv96(iso[,scale])  note: default scale=1
  converts iso to sv96.
 
iso=sv96_to_iso(sv96[,scale])  note: default scale=1
  converts sv96 to iso

av96=aperture_to_av96(aperture[,scale]) default scale=1000
  converts aperture to av96. f/2.0 is aperture=2000

aperture=av96_to_aperture(av96[,scale]) default scale=1000
  converts av96 to aperture

The ISO conversion is using the old CHDK equation for 'real' ISO. It needs to be updated to use the 1.3 conversion.
  I need to change the constant in the conversion, since I used the Wikipedia equation, but I don't think this function should be modified to include "Market" ISO. To do that, you would need a Real to Market conversion function.

I need to research this a little more, but in my Tlasper.lua script I just add a constant to the Real sv96 to get Market sv96. This is based on the assumption that adding 96 to real or market sv96 should double the ISO (Real or Market). This shows how I do it in my script so I can input Market ISO:
Code: [Select]
@param z ISO Max
@default z 400
@param s ISO Min
@default s 100

--(in half_shoot)
sv=get_sv96()
svdiff=iso_to_sv96(get_iso_market())-sv  -- real to market difference
svmin=iso_to_sv96(s)-svdiff -- min sv ISO 100 market default
svmax=iso_to_sv96(z)-svdiff

--Now, to print Market ISO you do this
print(sv96_to_iso(sv+svdiff))
This works perfectly up to Market ISO 800 on my cameras. Above that, I think Canon may be cheating a little by making Market ISO more sensitive than it really is. I need to test this some more.
Quote
Not sure I see the need for the optional 'scale' parameter in all of the functions - the level of inaccuracy in the integer conversion means you're not going to get much better than using a default value of 1000.
This would also simplify the code.
This is not true. As Tv96 gets larger, the shutter times go below 1/1000 second (0.001 second). You need a scale of 1000000 to
output in microseconds.

The idea is that within the normal range of shutter times, ISO, and Aperture values, a change of 1 tv96, sv96, and av96 should
always be able to show a change in the resulting Shutter Time, ISO or Aperture value. This is important when displaying
converted Shutter, ISO, and Aperture values so you can see that they are changing.

If you don't like the scale parameter, you don't have to use it since the default is a scale of 1000. But if you take it out, you won't be able to accurately input or output accurate fast shutter times in microseconds, and your other conversions may have less precision than desired for certain applications.
Quote
Edit2: The other option here is to use the imath library fixed point type for shutter speed and aperture (instead of multiplying everything by 1000 / 'scale').

Personally I would also lose the convert96 function and move the conversion code into the calling functions.

Edit: I also don't like the way the 'shutter_to_tv96' treats negative numbers as a special case so that -2000 and 500 both mean 1/2 second shutter speed.
The imath library doesn't have the capability to do microsecond precision, and it adds complexity to the scripts in that you have to do a lot of multiplying and dividing by 1000, plus rounding. My functions are much simpler to use, and will take up much less overall memory by reducing a lot of Lua code.

I originally had a single Lua function called "convert96", and I never moved the code to the new, multiple calling functions. That's on my to do list.

Again, if you don't like the negative shutter time feature, you don't have to use it. But for me, it's very useful for inputting and displaying fast shutter times in a standard, 1/t format instead of in microseconds (the only other option). I'd rather input my maximum shutter speed as -4000 (1/4000) than have to figure out that it's 250 microseconds (although you can do that if you want using a scale of 1000000).

I'm open to simplifying code and making it faster and more accurate, but please don't take out important and very useful features because you don't "like" them. Others will want to use them, and probably think of new, innovative ways to use them that we can't imagine right now.
Title: Re: Re: 1.3 development planning thread
Post by: philmoz on 24 / August / 2013, 00:22:03
As I work through lapser's patch file for his shot_histogram_request mods and remove things not related to that,  I stumbled on his "real world to APEX96" functions.

Code: [Select]
+    FUNC(shutter_to_tv96)
+    FUNC(tv96_to_shutter)
+    FUNC(iso_to_sv96)
+    FUNC(sv96_to_iso)
+    FUNC(aperture_to_av96)
+    FUNC(av96_to_aperture)
They are not really part of the shot_histogram & continuous shooting exposure adjust code so I guess I'll strip them out too.   

But is "somebody" going to add the equivalent as part of 1.3.0 (or as part of the real vs market ISO conversion) ?

I can do it but I'm assuming it needs to be tied to the fixes for ISO in 1.3.0?

UPDATE :  patch file of lapser's apex96 Lua conversion functions attached

My suggestion for this would be:
- put the conversion functions in shooting.c (note some are already there) so they can be called by uBasic and Lua
- implement the following functions:
Code: [Select]
    ISO_to_Sv96(n)             - 'n' = ISO value (can be either real or market value since conversion in 1.3 is identical)
    Sv96_to_ISO(sv96)
    ISO_real_to_market(n)      - convert ISO from real to market
    ISO_market_to_real(n)      - convert ISO from market to real
    Sv96_real_to_market(sv96)  - convert Sv96 from real to market
    Sv96_market_to_real(sv96)  - convert Sv96 from market to real
    Aperture_to_Av96(n)        - 'n' = 1000 * f-number (e.g. f/2.8 = 2800)
    Av96_to_Aperture(av96)     - returns 1000 * f-number
    uSec_to_Tv96(n)            - 'n' is shutter speed in microseconds
    Tv96_to_uSec(tv96)         - returns shutter speed in microseconds
    rational_to_Tv96(n,d)      - convert shutter speed expressed as a rational number (n/d)

I think this is clearer and keeps everything in consistent units.

I prefer to name the functions with the case as shown above; but I can live with everything in lower case if that's the consensus.

Phil.


Title: Re: Re: 1.3 development planning thread
Post by: lapser on 24 / August / 2013, 01:26:46
I think this is clearer and keeps everything in consistent units.

I prefer to name the functions with the case as shown above; but I can live with everything in lower case if that's the consensus.
Sounds pretty good. I like the case, too. I originally put the functions in shooting.c and tried to use the ones that were there, but I had trouble with the short to integer conversions, among other things, and decided it was easier to write them from scratch as integer functions. I could probably use the iso to market iso functions you just finished in shooting.c

I don't see the need for rational_to_Tv96(n,d). uSec goes up to 2147.483648 seconds with a 31 bit positive integer, doesn't it?

I do think we need a way to enter shutter times as 1/seconds, since that's the way the camera, and photographers think about fast shutter times. The spec for the G1X is 1/4000 seconds for fastest shutter time, for example. My script has a maximum and minimum shutter time. The maximum is in seconds, and the minimum is 1/seconds.

The way I did it is to interpret negative numbers as 1/n, which works well. It is similar to a negative exponent. To avoid overflow, it's probably better to interpret -n as 1/Sec instead of 1/uSec. But that makes the name "uSec" confusing, so maybe a new function
would be best, which would avoid the negative number confusion too. This is what the function would do, but we'd need a valid name for [1/Sec]:

[1/Sec]_to_Tv96(n)

Another problem is the accuracy of Sv96_to_ISO(sv96) at low ISO. I think that a change of 1 sv96 should always give a new ISO result. My SX50 goes down to 80 ISO. 80 to 160 ISO is 96 Sv96 units, but only 80 ISO units. We need at least ISO*10 to avoid this problem. Maybe ISO*1000 would be more consistent with the Aperture conversion function.
Title: Re: Re: 1.3 development planning thread
Post by: philmoz on 24 / August / 2013, 03:50:17
I think this is clearer and keeps everything in consistent units.

I prefer to name the functions with the case as shown above; but I can live with everything in lower case if that's the consensus.
Sounds pretty good. I like the case, too. I originally put the functions in shooting.c and tried to use the ones that were there, but I had trouble with the short to integer conversions, among other things, and decided it was easier to write them from scratch as integer functions. I could probably use the iso to market iso functions you just finished in shooting.c

I don't see the need for rational_to_Tv96(n,d). uSec goes up to 2147.483648 seconds with a 31 bit positive integer, doesn't it?

I do think we need a way to enter shutter times as 1/seconds, since that's the way the camera, and photographers think about fast shutter times. The spec for the G1X is 1/4000 seconds for fastest shutter time, for example. My script has a maximum and minimum shutter time. The maximum is in seconds, and the minimum is 1/seconds.

The way I did it is to interpret negative numbers as 1/n, which works well. It is similar to a negative exponent. To avoid overflow, it's probably better to interpret -n as 1/Sec instead of 1/uSec. But that makes the name "uSec" confusing, so maybe a new function
would be best, which would avoid the negative number confusion too. This is what the function would do, but we'd need a valid name for [1/Sec]:

[1/Sec]_to_Tv96(n)

Ummm, that's exactly what rational_to_Tv96 is for - rational_to_Tv96(1,4000)
But by specifying both numerator and denominator you aren't limited to 1/N values.

Alternatively the function could be rational_to_uSec and would be called as uSec_to_Tv96(rational_to_uSec(1,4000))

Quote
Another problem is the accuracy of Sv96_to_ISO(sv96) at low ISO. I think that a change of 1 sv96 should always give a new ISO result. My SX50 goes down to 80 ISO. 80 to 160 ISO is 96 Sv96 units, but only 80 ISO units. We need at least ISO*10 to avoid this problem. Maybe ISO*1000 would be more consistent with the Aperture conversion function.

A change of 1 Sv96 unit is 1/96th of an f-stop - a virtually undetectable change.
Being able to request ISO 80.52 versus 80 or 81 is unlikely to make any difference to the resulting image. If you really need a 1/96th stop change in exposure then just use Sv96 units and forget about ISO.

A scale factor for aperture is required because the f-number values aren't whole numbers - *1000 matches the existing CHDK code; but is really not necessary (*10 would probably work just as well).

Phil.
Title: Re: Re: 1.3 development planning thread
Post by: lapser on 24 / August / 2013, 11:21:05
Ummm, that's exactly what rational_to_Tv96 is for - rational_to_Tv96(1,4000)
But by specifying both numerator and denominator you aren't limited to 1/N values.
Oh, that makes sense then (sounds perfectly rational). I was thinking "d" meant it was a decimal number:  nnn.ddddd
I'm assuming n/d is in Seconds, not uSec then?

In Lua, I supposed you could make the numerator optional, defaulting to 1. I love optional parameters. Personally, I would probably never use a numerator other than 1. The main thing this function would be used for is inputting fast shutter speeds in (1/sec) format. Do you have a scenario where you would need a numerator other than 1? For simplicity, this would be better for my uses:

reciprocal_to_Tv96(sec)
Quote
A change of 1 Sv96 unit is 1/96th of an f-stop - a virtually undetectable change.
I was thinking more of the Sv96_to_ISO(sv96) function for output. My script varies sv96 1 unit at a time from 80 (min) to 1600(max), and outputs the log data in ISO, rather than sv96. But it's probably not worth the added complexity and confusion to allow more precise ISO units. I can always output the precise sv96 to the log if I want to show it changed.

Also, since all the other functions are all lower case, it's probably better to use lower case here too. I'm already having trouble keep things straight.
Title: Re: Re: 1.3 development planning thread
Post by: reyalp on 24 / August / 2013, 14:18:19
I like phils proposal. I agree with lapser that the names should be lowercase, since that is consistent with almost everything that is already in the api.

In Lua, I supposed you could make the numerator optional, defaulting to 1. I love optional parameters. Personally, I would probably never use a numerator other than 1. The main thing this function would be used for is inputting fast shutter speeds in (1/sec) format. Do you have a scenario where you would need a numerator other than 1? For simplicity, this would be better for my uses:
2/3 ?
3/4 ?
It also lets you sue the same function for long exposures, since you can use, e.g. 120/1 for a 2 minute exposure.

I'm only fond of optional parameters where the behavior is fairly obvious. Assuming 1/x if there is only one number might fit the bill in this case, though putting the 1 in isn't much work.
Title: Re: Re: 1.3 development planning thread
Post by: lapser on 24 / August / 2013, 15:26:57
In Lua, I supposed you could make the numerator optional, defaulting to 1. I love optional parameters. Personally, I would probably never use a numerator other than 1. The main thing this function would be used for is inputting fast shutter speeds in (1/sec) format. Do you have a scenario where you would need a numerator other than 1? For simplicity, this would be better for my uses:
2/3 ?
3/4 ?
It also lets you sue the same function for long exposures, since you can use, e.g. 120/1 for a 2 minute exposure.
2/3 and 3/4 never appear as shutter times on my cameras, or in EXIF data that I've ever seen. But I don't see any reason to eliminate the capability.

I do like having a denominator, so 120/1 is 120 seconds, instead of 120000000. Of course, then the denominator just becomes a scale factor, like I have in my current functions:

I doubt I would ever use usec_to_tv96. Instead, I would enter it as microseconds:

rational_to_tv96(msec,1000)

I don't like the name "rational" since it doesn't include the unit, which is seconds/d. How about:

rsec_to_tv96(n,d)
rsec= rational seconds. It goes with usec=microseconds.
===
Also, since both uBasic and Lua are in modules, wouldn't it be better to duplicate the code in both? That saves memory when scripts aren't running, and you don't need to add all the functions to the module export list. Do you need to be able to call the new functions from CHDK routines in addition to scripts?

And do we really need to add all new functions to uBasic? It seems obsolete with Lua available.
Title: Re: Re: 1.3 development planning thread
Post by: waterwingz on 24 / August / 2013, 18:05:56
And do we really need to add all new functions to uBasic?
Yes,  I believe that we do.  Not every newbie with "get" Lua right away and many of them just want to do something simple with CHDK.
Title: Re: Re: 1.3 development planning thread
Post by: srsa_4c on 25 / August / 2013, 09:01:35
Yes,  I believe that we do.  Not every newbie with "get" Lua right away and many of them just want to do something simple with CHDK.
+ uBasic requires less memory, which can be significant on some cameras
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: philmoz on 31 / August / 2013, 03:02:38
I've added the conversion functions in revision 3052 (trunk).
I went with 'seconds_to_tv96(n,d)' instead of 'rational_to_sv96(n,d)' after discussion with reyalp and waterwingz on IRC.

Phil.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: waterwingz on 31 / August / 2013, 11:12:03
Updated :
http://chdk.wikia.com/wiki/Script_commands#APEX96_Conversion_Functions (http://chdk.wikia.com/wiki/Script_commands#APEX96_Conversion_Functions)
http://chdk.wikia.com/wiki/CHDK_Scripting_Cross_Reference_Page#All_Scripting_Functions (http://chdk.wikia.com/wiki/CHDK_Scripting_Cross_Reference_Page#All_Scripting_Functions)

Its consistent with the rest of the scripting documentation as its concise and not too useful.  I'll see if I can make it a bit better
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: waterwingz on 31 / August / 2013, 12:47:55
Wrote a little test script that I had planned to break into pieces and add to the wiki write-ups as examples.
Code: [Select]
--[[
@title APEX96
@param i ISO value
@default i 200
@param l Log
@default l 0
@range l 0 1
--]]
set_console_layout(0, 0, 44, 16)
print_screen(l)

sv96 = iso_to_sv96(i)
print("ISO "..i.." = SV96 "..sv96)
iso=sv96_to_iso(sv96)
print("SV96 "..sv96.." = ISO" , iso )

isom=iso_real_to_market(i)
isor=iso_market_to_real(i)
print("ISO "..i.." real  = ISO"..isom.." market")
print("ISO "..i.." market = ISO"..isor.." real")

sv96m=sv96_real_to_market(sv96)
sv96r=sv96_market_to_real(sv96)
print("SV96 "..sv96.." real = "..sv96m.." market")
print("SV96 "..sv96.." market = "..sv96r.." real")

fstop=5600
av96 = aperture_to_av96(fstop)
print("f"..(fstop/1000).."." ..((fstop%1000)/100).." = AV96 "..av96)
fstop = av96_to_aperture(av96)
print("AV96 "..av96.." = f"..(fstop/1000).."."..(fstop%1000)/100)

shutter=10000
tv96=usec_to_tv96(shutter)
print((shutter/1000000).."sec ".. (shutter/1000).." msec = "..tv96.." in apex96 units" )
shutter=tv96_to_usec(tv96)
print("TV96 "..tv96.." = "..(shutter/1000000).."sec ".. (shutter/1000).." msec")

n=1
d=60
tv96=seconds_to_tv96(n,d)
print(n.."/"..d.." = ", tv96, "in apex96 units" )
shutter=tv96_to_usec(tv96)
print("TV96 "..tv96.." = "..(shutter/1000000).."sec ".. (shutter/1000).." msec")
The edited resulting log file looks like this :
Code: [Select]
ISO 200 = SV96 576
SV96 576 = ISO 200
ISO 200 real  = ISO329 market        <--- really ?
ISO 200 market = ISO122 real         <--- can this be true ?
SV96 576 real = 645 market            <-- here too
SV96 576 market = 507 real            <-- and here
f5.6 = AV96 477
AV96 477 = f5.5                   <-- a slight rounding error
0sec 10 msec = 638 in apex96 units
TV96 638 = 0sec 9 msec          <-- more rounding tweaks needed
1/60 =  567 in apex96 units
TV96 567 = 0sec 16 msec
The rounding errors in Tv and Av conversions are easy to adjust in the script. 

But the output of the ISO real to market seems strange!  I would not have expected that big a different on my A1200.  Maybe I'm using the new functions incorrectly?
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: reyalp on 31 / August / 2013, 13:06:27
But the output of the ISO real to market seems strange!  I would not have expected that big a different on my A1200.  Maybe I'm using the new functions incorrectly?
They look correct to me. The standard difference is 69 APEX96.

APEX96 to ISO (in whichever system) is 3.125*(2(APEX96/96))
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: waterwingz on 31 / August / 2013, 13:09:39
But the output of the ISO real to market seems strange!  I would not have expected that big a different on my A1200.  Maybe I'm using the new functions incorrectly?
They look correct to me. The standard difference is 69 APEX96.

APEX96 to ISO (in whichever system) is 3.125*(2(APEX96/96))
Thanks.   Despite all the conversations about this recently ( http://chdk.setepontos.com/index.php?topic=10341.0 (http://chdk.setepontos.com/index.php?topic=10341.0) ) its still comes as a bit of a shock when I see the difference in another context.  No wonder people have been somewhat upset over the years.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: lapser on 31 / August / 2013, 13:59:24
First of all, great job, as usual, Phil. I love the way you implemented it, and the seconds_to_tv96 function should do all I want in a much clearer way than the negative time input and scale factor I used. The docs that waterwingz wrote are perfect too Thanks!

I noticed that Phil uses a (short) argument for a function that I thought was defined to have an (int) argument. I didn't realize the compiler would implicitly convert in that case. It's nice to learn something new.

Code: [Select]
ISO 200 = SV96 576
ISO 200 real  = ISO329 market        <--- really ?
ISO 200 market = ISO122 real         <--- can this be true ?
SV96 576 real = 645 market            <-- here too
SV96 576 market = 507 real            <-- and here
The idea is that doubling the market ISO should double the real ISO. This translates to adding 96 to the real or market sv96. So the sv96 conversion is a constant offset:

sv96 market = sv96 real + offset.

In my cameras, the offset it 59, but Canon picks the offset for each camera depending on the properties of the sensor. I think they're trying to match the exposure of a old style film camera with various ISO film speeds.

sv96 addition is ISO multiplication, so:

ISO market = ISO real * 2^(offset/96).
ISO market = ISO real *1.53 -- for a sv96 offset of 59

So ISO 200 real = ISO 306 Market on my cameras. Your camera sv96 offset must be a little larger.

I think maybe the purpose for the sv96 "base" and "delta" propcases may be that higher ISO film (physical  film) speeds aren't exactly double the next lower film speed. ISO 3200 film isn't exactly twice as sensitive as ISO 1600 film. The constant sv96 offset for real and market holds true up to ISO 800 on my cameras, but above that it isn't the same, I've found.

I'm not sure how Phil handled this, but I'm happy with it however he did it. I just ignored it in my script, and used a constant offset. I only used market ISO for input and display, and all the exposure changes were s96 real.
***
I see phil and reyalp have answered this while I'm typing, and phil uses 69 for the conversion. Is this for all cameras?

[EDIT]
This is how I find the offset in my script:
Code: [Select]
sv=get_sv96()
svdiff=iso_to_sv96(get_iso_market())-sv  -- real to market difference
svmin=iso_to_sv96(s)-svdiff -- min sv ISO 100 market default
svmax=iso_to_sv96(z)-svdiff
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: reyalp on 31 / August / 2013, 14:30:35
I see phil and reyalp have answered this while I'm typing, and phil uses 69 for the conversion. Is this for all cameras?
All modern cameras, some early vxworks cams are different. You can go and re-read the market vs. real thread waterwingz linked if you want the gory details.

It is highly unlikely that the actual difference on your cameras is 59. If this was calculated using the old ISO code, it was probably an error. Though the 1/10th of a stop isn't likely to have a noticeable impact.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: lapser on 31 / August / 2013, 15:09:33
It is highly unlikely that the actual difference on your cameras is 59. If this was calculated using the old ISO code, it was probably an error. Though the 1/10th of a stop isn't likely to have a noticeable impact.
That's probably it. I used the Wikipedia equation, so the constant is off. I'll see what it comes up with after I update to the new trunk and get my mods working again. Thanks.

[EDIT]
I updated to the latest trunk and took out all my Apex96 functions successfully. Then I modified my time lapse script to use the new functions. So far, it looks like they're working correctly, and give correct results. The offset now comes out to 69, like it should. Good work everyone!

seconds_to_tv96(n,d) is a lot more flexible, so I didn't need to use usec_to_tv96(usec). Thanks for including seconds_to_tv96, and the name is perfect.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: lapser on 10 / September / 2013, 15:58:33
I've uncovered a precision problem that stems from the use of (usec) in the shutter time to tv96 conversion functions.
Code: [Select]
float shooting_get_shutter_speed_from_tv96(short tv96){//function here}
static int luaCB_tv96_to_usec( lua_State* L )
{
  lua_pushnumber(L, (int)(shooting_get_shutter_speed_from_tv96(luaL_checknumber(L, 1)) * 1000000.0 + 0.5));
  return 1;
}
I input the max shutter speed as 1/seconds. A typical maximum is 1/3200 seconds, entered like this.

tv96max=seconds_to_tv96(1,3200)

This converts to tv96=1118, which looks correct.  However, to convert it back to 1/seconds, you have to compute:

tv96_to_usec(-1118)

This converts 3,200.0 seconds, which is returned as:

3,200,000,000 microseconds. The maximum positive integer is:
2,147,483,647   so I end up with 1/2147 seconds instead of 1/3200.

My feeling is that we need to get rid of the usec functions and use

tv96_to_seconds(tv96,multiplier)
and
seconds_to_tv96(seconds,divisor)


Title: Re: 1.3 development proposal - exposure conversion functions
Post by: reyalp on 10 / September / 2013, 16:25:26
I've uncovered a precision problem that stems from the use of (usec) in the shutter time to tv96 conversion functions.
...
That seems more like a problem in how you are trying to use it to me. tv96_to_usec correctly handles tv96 values that can actually be used by the firmware.  tv96 values that cannot be converted to a 32 bit integer usec value are invalid by definition, since that's what the camera actually uses to specify the exposure length.

If you choose to feed it tv96 values outside of that range, you get bad results. So don't do that?
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: lapser on 10 / September / 2013, 18:53:45
I've uncovered a precision problem that stems from the use of (usec) in the shutter time to tv96 conversion functions.
...
If you choose to feed it tv96 values outside of that range, you get bad results. So don't do that?
You snipped the important part. tv96_to_usec(tv96) is used for displaying the shutter time in a human readable format. The format should correspond to what is shown on the camera, or in the EXIF data. The EXIF data is displayed in Windows as 1/3200 seconds, and all the faster shutter times are shown on the camera as 1/seconds. Microseconds just aren't used for showing shutter times.

Which is more understandable for photographers?

1/3200 sec
or
312 usec

It would probably work if the unit was 100 usec,

tv96_to_usec100().

but it's much more flexible to do it like this:
tv96_to_second(tv96,scale or multiplier)
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: philmoz on 10 / September / 2013, 20:22:31
I've uncovered a precision problem that stems from the use of (usec) in the shutter time to tv96 conversion functions.
...
If you choose to feed it tv96 values outside of that range, you get bad results. So don't do that?
You snipped the important part. tv96_to_usec(tv96) is used for displaying the shutter time in a human readable format. The format should correspond to what is shown on the camera, or in the EXIF data. The EXIF data is displayed in Windows as 1/3200 seconds, and all the faster shutter times are shown on the camera as 1/seconds. Microseconds just aren't used for showing shutter times.

Which is more understandable for photographers?

1/3200 sec
or
312 usec

It would probably work if the unit was 100 usec,

tv96_to_usec100().

but it's much more flexible to do it like this:
tv96_to_second(tv96,scale or multiplier)

1000000 / tv96_to_usec(n)

Phil.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: lapser on 10 / September / 2013, 23:55:42
1000000 / tv96_to_usec(n)
As usual, Phil figures out the solution.

I actually need 1/msec precision, but I can get that, barely within 31 bits, like this:

1,000,000,000/tv96_to_usec(n)  -- without the commas

My 1/3200 shutter time comes out to 1/3205 after the conversion. My old one came out to 1/3201.

I think there also is a precision problem with using (float) instead of (double) in this function:
Code: [Select]
float shooting_get_shutter_speed_from_tv96(short tv96)
{
    return pow(2,((float)(-tv96))/96.0);
}
//how about changing it to:
double shooting_get_shutter_speed_from_tv96(short tv96)
{
    return pow(2,((double)(-tv96))/96.0);
}
Search for the function in all source files. There's only a few places that need to be changed, i.e. cast to (float). Most of the time, the result is already cast to (int).  Also, I think pow() expects a (double) 2nd argument, so the cast to float is cast back to (double) after the division, which wastes precision.

(float) only has about 6 or 7 digits of precision, so when you multiply a float by 1,000,000 you're not getting accurate microseconds for values over 1 second or so. Basically, you're computing values to put into 10 digit integers, using 7 digit floating point arithmetic. So it should be using double. For consistency, I would like to see all the conversion functions changed from float to double.

============

Here's how I modified my function to print shutter times using Phil's idea. I changed it so it doesn't start using 1/seconds format until it gets to 1/2 second, which matches what the camera displays and puts into the EXIF (i.e. 0.6 seconds instead of 1/1.66)
Code: [Select]
function seconds(tv) -- tv96 to time string i.e. print(seconds(tv))
  local pre=""
  if(tv>=96)then
    tv=1000000000/tv96_to_usec(tv)
    pre="1/"
  else
    tv=tv96_to_usec(tv)/1000
  end
  local ti=tv/1000 -- integer part
  if(ti>1000)then ti=(ti/10)*10 end -- only 3 digits precision
  local ts=string.format("%s%u.%03u",pre,ti,tv%1000) -- xx.xxx or 1/xx.xxx
  if(ti>1)then -- truncate digits to reflect decimal precision
    if(ti>149)then ti=-5
    elseif(ti>14)then ti=-3
    else ti=-2 end
    ts=string.sub(ts,1,ti)
  end
  return ts
end
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: philmoz on 11 / September / 2013, 06:16:14
My 1/3200 shutter time comes out to 1/3205 after the conversion. My old one came out to 1/3201.

I tried your code and it gives exactly the same result (3205).

The difference between 1/3200 and 1/3205 is less then 1/2 microsecond - hardly likely to make a visible difference to any image exposure.

Quote
I think there also is a precision problem with using (float) instead of (double) in this function:
Code: [Select]
float shooting_get_shutter_speed_from_tv96(short tv96)
{
    return pow(2,((float)(-tv96))/96.0);
}
//how about changing it to:
double shooting_get_shutter_speed_from_tv96(short tv96)
{
    return pow(2,((double)(-tv96))/96.0);
}
Search for the function in all source files. There's only a few places that need to be changed, i.e. cast to (float). Most of the time, the result is already cast to (int).  Also, I think pow() expects a (double) 2nd argument, so the cast to float is cast back to (double) after the division, which wastes precision.

(float) only has about 6 or 7 digits of precision, so when you multiply a float by 1,000,000 you're not getting accurate microseconds for values over 1 second or so. Basically, you're computing values to put into 10 digit integers, using 7 digit floating point arithmetic. So it should be using double. For consistency, I would like to see all the conversion functions changed from float to double.

How exactly would a difference of a few microseconds affect an exposure > 1 second in length?

Phil.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: Microfunguy on 11 / September / 2013, 06:59:59

I actually need 1/msec precision

Why ?

What does 1/msec mean, do you mean one msec ?

Title: Re: 1.3 development proposal - exposure conversion functions
Post by: lapser on 11 / September / 2013, 15:15:20
I tried your code and it gives exactly the same result (3205).
I'm not sure which code you're talking about. I'm comparing it with my initial function that used (double) internally and returned an integer result, with a scale factor.

If you're OK with casting a 24 bit float to a 32 bit integer, and the resulting loss of precision with larger numbers, then I guess there's not much I can do about it. You usually like to write optimized code, so I'm surprised you're resisting switching to double when it's so simple.  Remember, you're multiplying a float by 1,000,000 before casting to (int).
Quote
The difference between 1/3200 and 1/3205 is less then 1/2 microsecond - hardly likely to make a visible difference to any image exposure.
I'm not talking about setting exposure. I'm talking about displaying the exposure in a human readable format, like the camera does in the EXIF and on screen when you take a picture. It displays decimal seconds for exposures longer than 0.5 seconds, and "1/seconds" for exposures shorter than 1/2 seconds.

What does 1/msec mean, do you mean one msec ?
There are 96 unique shutter times between 1/2 and 1/4 second, for example.  I need more decimal digits between 2 and 4. I print out:

1/2.000  to 1/4.000

So I need 1/shutter time in seconds*1000, or msec, to get that precision.

Title: Re: 1.3 development proposal - exposure conversion functions
Post by: Microfunguy on 11 / September / 2013, 16:05:57
There are 96 unique shutter times between 1/2 and 1/4 second

So what, you are not under obligation to make use of them.

Quote
I need more decimal digits between 2 and 4.

You might, photographers do not.

Is this about 'the joy of programming' or practical photography ?

Generally, 48 APEX96 units is sufficient precision for me.
For HDR bracketed sequences 128 units is just fine.

Title: Re: 1.3 development proposal - exposure conversion functions
Post by: lapser on 11 / September / 2013, 18:15:07
Is this about 'the joy of programming' or practical photography ?
Generally, 48 APEX96 units is sufficient precision for me.
For HDR bracketed sequences 128 units is just fine.
I can't seem to get it across that the function, tv96_to_usec(tv96) is NOT about setting exposure. You set the exposure with tv96, and you already have that!

I do time lapses of sunsets. I change the exposure from one picture to the next by 1 tv96 unit. If you change it more than that, you see a "flash" in the dark portions of the video. It's not about how the individual pictures look, it's about how the video looks when you switch between the two pictures. I'm not using the 2 pictures to make a single picture, like with HDR. I'm displaying the two pictures consecutively in a video.

While taking each picture, I show the shutter time for that picture on the screen using tv96_to_usec(tv96). It's important that the value displayed changes when tv96 is incremented by 1, and that fast shutter speed be displayed as fractions in the form 1/x.xxx.  This requires precision since the changes are small. I had it working fine with my original function, tv96_to_shutter(tv96,scale), which used (double) for it's calculations, and output (int) after rounding. But by insisting on a fixed scale of 1,000,000 the function is pushing the limits of 32 bit integers, and exceeding the limits of 24 bit floating point. The imath library uses a scale of 1,000 and computes with (double) for a reason.

But I still think the best solution is to add the function:

tv96_to_seconds(tv96,multiplier)
tv96_to_seconds(tv96,1000000) is the same as tv96_to_usec(tv96)
It allows me to use tv96_to_seconds(-tv96,1000) for the 1/x.xxxx output format without overflow
This function is essentially the inverse of the current function:

seconds_to_tv96(seconds,divisor)
seconds_to_tv96(usec,1000000)is the same as usec_to_tv96(usec)

For now, I guess tv96_to_seconds(..) will be specific to my builds.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: Microfunguy on 11 / September / 2013, 18:51:33
Fair enough, I have not read the entire thread.

Is there anything special about seconds, why not just display the Tv96 number ?

Title: Re: 1.3 development proposal - exposure conversion functions
Post by: philmoz on 11 / September / 2013, 19:37:38
While taking each picture, I show the shutter time for that picture on the screen using tv96_to_usec(tv96). It's important that the value displayed changes when tv96 is incremented by 1, and that fast shutter speed be displayed as fractions in the form 1/x.xxx.  This requires precision since the changes are small. I had it working fine with my original function, tv96_to_shutter(tv96,scale), which used (double) for it's calculations, and output (int) after rounding. But by insisting on a fixed scale of 1,000,000 the function is pushing the limits of 32 bit integers, and exceeding the limits of 24 bit floating point. The imath library uses a scale of 1,000 and computes with (double) for a reason.

Can you provide a real example where your seconds(tv) function does not give a different value to seconds(tv+1) or seconds(tv-1)?

Phil.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: lapser on 11 / September / 2013, 20:55:18
Can you provide a real example where your seconds(tv) function does not give a different value to seconds(tv+1) or seconds(tv-1)?
I haven't had a chance to test the 1000000000/tv96_to_usec(tv96) method yet. Just looking at it, you can tell it's ripe for overflow. Plus, it only has 3 digits of precision in the result, so the low digit of 1/3200 isn't valid. I can't add another 0 to the numerator to get another digit, because that's a 33 bit signed number. The problem isn't producing different values. The problem is that there aren't enough digits of precision.

But why do you demand an example when you're casting 24 bit (float) to 32 bit (int)? It's obvious that (double) should be used. There aren't any time critical calculations involved. What's the advantage of using (float) instead of (double) here, anyway?

You also should be able to use tv96_to_usec(-tv96) to get 1/xx.xxx shutter times. 1/3200 needs tv96=-1188, but that evaluates to 1/2147, which is the max positive int. Anything larger than tv96=1064 results in 2147 as a result. The fixed usec unit is very limiting.

You do get the same sv96_to_iso(sv96) results for a change of 1 sv96  when you start at ISO 80, for example. There are 96 sv96 units between ISO 80 and ISO 160, but only 80 ISO units. People may also want to use lower ISO than 80. This is why I added an optional scale to ISO. I'm not as worried about this as the shutter time problem, although the SX50 does start at 80 ISO.
Is there anything special about seconds, why not just display the Tv96 number ?
I used to do that, but it's more understandable to input and output in seconds. It's like saying, "I'll call you back in -576 tv96" instead of "I'll call you in a minute."

I usually want to enter the maximum shutter time in seconds, i.e. 15 seconds, and the minimum as 1/seconds, i.e. 1/3200 seconds. I don't think microseconds is a unit that's used in photography much. The seconds_to_tv96() function is perfect for this:

tv96Max=seconds_to_tv96(tmax,1)
tv96Min=seconds_to_tv96(1,tmin)

It's reasonable to want the seconds display to be 1/xx.xxx for shutter times less than 1/2 second, and xx.xxxx for times longer than 1/2 second. That's what my seconds(tv) Lua function does, and that's where I discovered the overflow, and precision problems with tv96_to_usec(tv96). tv96_to_seconds(tv96,1000) is equivalent to my original tv96_to_shutter(tv96,scale), which worked well.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: waterwingz on 11 / September / 2013, 20:56:49
Fair enough, I have not read the entire thread.  Is there anything special about seconds, why not just display the Tv96 number ?
The whole point of this thread and the resulting changes to CHDK were to allow the UI provided by CHDK scripts to work easily in the units a camera owner expects to see ( seconds, f-stop,  ISO sensitivity).  Showing Tv96 values tends to be confusing to photographers who are not programmers.

Title: Re: 1.3 development proposal - exposure conversion functions
Post by: Microfunguy on 11 / September / 2013, 21:49:54
It's like saying, "I'll call you back in -576 tv96" instead of "I'll call you in a minute."to_seconds(tv96,1000) is equivalent to my original tv96_to_shutter(tv96,scale), which worked well.

Well, -576 is instantly recognisable as 64 seconds.

576/96 = 6, 2^6 = 64, it is a negative number so that must be the numerator rather than the denominator.

Just a number, as long as we can see it change ........ 
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: philmoz on 11 / September / 2013, 21:56:53
Can you provide a real example where your seconds(tv) function does not give a different value to seconds(tv+1) or seconds(tv-1)?
I haven't had a chance to test the 1000000000/tv96_to_usec(tv96) method yet. Just looking at it, you can tell it's ripe for overflow. Plus, it only has 3 digits of precision in the result, so the low digit of 1/3200 isn't valid. I can't add another 0 to the numerator to get another digit, because that's a 33 bit signed number. The problem isn't producing different values. The problem is that there aren't enough digits of precision.

But why do you demand an example when you're casting 24 bit (float) to 32 bit (int)? It's obvious that (double) should be used. There aren't any time critical calculations involved. What's the advantage of using (float) instead of (double) here, anyway?

I was trying to be polite. My analysis shows that the maximum difference you can possibly get using double instead of float is 0.001%. That's 1/100,000th of a second.

Now if you can find a real world example that proves otherwise please post it.

Quote
You also should be able to use tv96_to_usec(-tv96) to get 1/xx.xxx shutter times. 1/3200 needs tv96=-1188, but that evaluates to 1/2147, which is the max positive int. Anything larger than tv96=1064 results in 2147 as a result. The fixed usec unit is very limiting.

As reyalp already explained that's not the purpose of the function. Just because you want to abuse it doesn't change that fact.

Phil.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: lapser on 13 / September / 2013, 04:01:26
As reyalp already explained that's not the purpose of the function. Just because you want to abuse it doesn't change that fact.
The purpose of the function is to convert tv96 into something photographers can understand. Photographers don't understand shutter times in microseconds. They understand shutter times in fractions (1/seconds).

The function is just 2^x with some constants. 2^(-x) = 1/(2^x). It's not abusing the function to expect that to be true, and to expect it to be able to output a value of 5,000, corresponding to a 1/5000 second shutter time. The function is crippled, not abused.

As far as casting float to int, I can't believe you'd actually argue to keep that sloppy code in CHDK. You still haven't given me a reason to use float instead of double. I can give you several reasons to use double.

You get about 3 extra digits of precision in your int values.
You're casting int to short to float to double and back and forth so much it's hard to follow.
You're doing all your calculations in double anyway, and just throwing away all that precision by casting double to float.
Truncation errors get worse the more calculations you do with the result.

Here's all the code involved. It should be in a textbook for how not to do calculations:

Code: [Select]
extern double pow(double x, double y); //from math.h

float shooting_get_shutter_speed_from_tv96(short tv96) //from shooting.c (worthless cast to short too)
{
    return pow(2,((float)(-tv96))/96.0);
}

static int luaCB_tv96_to_usec( lua_State* L ) //from luascript.c
{
  lua_pushnumber(L, (int)(shooting_get_shutter_speed_from_tv96(luaL_checknumber(L, 1)) * 1000000.0 + 0.5));
  return 1;
}

// All I'm asking for is:    tv96_to_seconds(tv96,scale)
static int luaCB_tv96_to_seconds( lua_State* L ) //to be added to luascript.c
{
  lua_pushnumber(L, (int)(shooting_get_shutter_speed_from_tv96(luaL_checknumber(L, 1)) * luaL_checknumber(L, 2) + 0.5));
  return 1;
}
OK, we've argued about this enough. Let's move on to more important things. I'll keep using a custom build that does what I need and not bug you any more about this.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: lapser on 13 / September / 2013, 16:48:32
Thinking about this overnight, I think I see where the disagreements come from, and how I can proceed without getting into any more of these kind of conflicts. First, let me apologize if my tone came across as rude or arrogant. I think you're all really incredible programmers, and that Phil is in a league by himself.

The CHDK menus provide an interface between the user and the camera operating system. As a user interface, menu functions must choose how to present data to the user, and accept data from the user, including the units and range for that data. The shutter time short override menu function uses 10 usec units, for example. The long shutter override menu function uses units of 1 second, with a somewhat excessive maximum time of 10 days.

The Apex96 conversion functions for scripts, as written, are user interface functions. They choose the units, and limit the range of the input and output based on those units. However, the script is what provides the user interface that presents and accepts data from the user. Script functions should be written as operating system functions, not user interface functions. The script is then free to provide the user interface, including choosing the units best suited for each application.

My philosophy is that script functions, as operating system functions, should provide maximum flexibility, precision, and efficiency to the script. If we all go forward with this in mind, scripts in CHDK can become incredibly powerful. I'm sure Phil and the other CHDK geniuses can come up with ways to do this that are much better than mine. For example, Phil's idea of the seconds_to_tv96(numerator, denominator) function is a much more flexible and clear method than my original shutter_to_tv96(t,scale) function, with -t indicating 1/t.

Smartphones have already implemented these ideas. The user interface to smartphones is all done with scripts (apps). Partly because of this, smartphone camera apps are taking over the point and shoot market, despite the limited capabilities of their tiny lenses and sensors in the phones.

The only way I can go from here is to change the current Apex96 functions from fixed unit user interface functions to flexible operating system functions, and use them in my own builds and scripts. Then I'll post a diff of the changes for others who might find them useful. I'll have to accept that maximizing script flexibility and capability is not the direction CHDK is going at the moment.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: reyalp on 13 / September / 2013, 17:04:39
The purpose of the function is to convert tv96 into something photographers can understand.
I disagree, the purpose is to convert tv96 values into microseconds. The valid values are limited to the same range of values the camera can actually use, since it ultimately uses an integer number of microseconds. This seems very clear and well defined to me. It's not a generic power function, it converts between the two time systems the camera actually uses.

The fact that you want to pass a negative value to get the inverse so you can display it as a fraction is a problem you have created for yourself.
Quote
As far as casting float to int, I can't believe you'd actually argue to keep that sloppy code in CHDK. You still haven't given me a reason to use float instead of double. I can give you several reasons to use double.
I don't care if it's a float or a double, but when the reason is that you need to distinguish between 1/3201 and 1/3205 it tells me that I probably don't need to spend any more time thinking about it.

If you want to log values for analysis, you should probably stick to native values like APEX96 or microseconds. (It should be noted that within the range it operates, Canon apex2us likely does not always give exactly the same results as our version). If you are going to do calculations on the exposure, you should do them all in one system (almost certainly APEX96), and only convert the final inputs or outputs if needed. This will give far better precision than any amount of tweaking the conversion functions.

If you want pretty values for display, prettify them however suits your fancy and accept that the pretty values will have less precision than the native values. Canon's pretty values are off by as much as a 1 second from the actual value...
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: lapser on 27 / September / 2013, 23:02:46
These are the changes I added to my CHDK custom build that correct the problems with the shutter time conversions. It doesn't look like anyone else wants this in the trunk, so I won't bother with a patch file. Unfortunately, I can't write an acceptable shutter time display function with the usec function as is.

The only change for scripts is a new, optional scale factor, which defaults to usec:

tv96_to_usec(tv96[,scale])

Code: [Select]
//in shooting.h
extern short shooting_get_tv96_from_shutter_speed(double t); //changed to double
extern double shooting_get_shutter_speed_from_tv96(short tv96); //changed to double

//in shooting.c
short shooting_get_tv96_from_shutter_speed(double t) //changed to double
{
    if (t > 0)
    {
        t = ((96.0 * -log(t)) * inv_log_2);
        if (t < 0)
            return (short)(t - 0.5);
        return (short)(t + 0.5);
    }
    return -10000;
}

double shooting_get_shutter_speed_from_tv96(short tv96) //changed to double
{
    return pow(2,((double)(-tv96))/96.0);
}

//in luascript.c
static int luaCB_usec_to_tv96( lua_State* L )
{
  lua_pushnumber(L, shooting_get_tv96_from_shutter_speed((double)luaL_checknumber(L, 1)/1000000.0));
  return 1;
}

static int luaCB_tv96_to_usec( lua_State* L )
{
  lua_pushnumber(L, (int)(shooting_get_shutter_speed_from_tv96(luaL_checknumber(L, 1)) *
    (double)luaL_optnumber(L, 2, 1000000) + 0.5));
  return 1;
}
The lua function to convert tv96 to a time string becomes much simpler. Also, using a scale factor returns rounded values based on that scale. Rounding to the nearest usec, as the current function does, isn't  useful.

Here's the lua time string function that works with these changes:
Code: [Select]
function seconds(tv) -- tv96 to time string i.e. print(seconds(tv))
  local pre=""
  if(tv>=96)then
    tv=-tv
    pre="1/"
  end
  tv=tv96_to_usec(tv,1000)
  local ti=tv/1000 -- integer part
  local ts=string.format("%s%u.%03u",pre,ti,tv%1000) -- xx.xxx or 1/xx.xxx
  if(ti>1)then -- truncate digits to reflect decimal precision
    if(ti>149)then ti=-5
    elseif(ti>14)then ti=-3
    else ti=-2 end
    ts=string.sub(ts,1,ti)
  end
  return ts
end
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: philmoz on 28 / September / 2013, 03:55:26
These are the changes I added to my CHDK custom build that correct the problems with the shutter time conversions. It doesn't look like anyone else wants this in the trunk, so I won't bother with a patch file. Unfortunately, I can't write an acceptable shutter time display function with the usec function as is.

The only change for scripts is a new, optional scale factor, which defaults to usec:

tv96_to_usec(tv96[,scale])

Code: [Select]
//in shooting.h
extern short shooting_get_tv96_from_shutter_speed(double t); //changed to double
extern double shooting_get_shutter_speed_from_tv96(short tv96); //changed to double

//in shooting.c
short shooting_get_tv96_from_shutter_speed(double t) //changed to double
{
    if (t > 0)
    {
        t = ((96.0 * -log(t)) * inv_log_2);
        if (t < 0)
            return (short)(t - 0.5);
        return (short)(t + 0.5);
    }
    return -10000;
}

double shooting_get_shutter_speed_from_tv96(short tv96) //changed to double
{
    return pow(2,((double)(-tv96))/96.0);
}

//in luascript.c
static int luaCB_usec_to_tv96( lua_State* L )
{
  lua_pushnumber(L, shooting_get_tv96_from_shutter_speed((double)luaL_checknumber(L, 1)/1000000.0));
  return 1;
}

static int luaCB_tv96_to_usec( lua_State* L )
{
  lua_pushnumber(L, (int)(shooting_get_shutter_speed_from_tv96(luaL_checknumber(L, 1)) *
    (double)luaL_optnumber(L, 2, 1000000) + 0.5));
  return 1;
}
The lua function to convert tv96 to a time string becomes much simpler. Also, using a scale factor returns rounded values based on that scale. Rounding to the nearest usec, as the current function does, isn't  useful.

Here's the lua time string function that works with these changes:
Code: [Select]
function seconds(tv) -- tv96 to time string i.e. print(seconds(tv))
  local pre=""
  if(tv>=96)then
    tv=-tv
    pre="1/"
  end
  tv=tv96_to_usec(tv,1000)
  local ti=tv/1000 -- integer part
  local ts=string.format("%s%u.%03u",pre,ti,tv%1000) -- xx.xxx or 1/xx.xxx
  if(ti>1)then -- truncate digits to reflect decimal precision
    if(ti>149)then ti=-5
    elseif(ti>14)then ti=-3
    else ti=-2 end
    ts=string.sub(ts,1,ti)
  end
  return ts
end

So what you really need is a function to generate a human readable string from the Tv96 shutter speed value?

Since this would also be useful for ubasic it should probably be in the core C code.

Phil.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: waterwingz on 28 / September / 2013, 10:28:36
So what you really need is a function to generate a human readable string from the Tv96 shutter speed value?
Can't find the links right now,  but I believe we've discussed this in a more general way a couple of times.   

To make my script UI's "pretty",  I'm still not using the new APEX96 functions to create output strings.  Nothing wrong with the functions but what I want is shutter speeds in the same increments that Canon provides so that they match the exif values. So for example, any tv96 value between 560 & 592 is displayed as 1/60 sec.

Code: [Select]
tv_ref = {    -- note : tv_ref values set 1/2 way between shutter speed values
-608, -560, -528, -496, -464, -432, -400, -368, -336, -304,
-272, -240, -208, -176, -144, -112,  -80,  -48,  -16,   16,
  48,   80,  112,  144,  176,  208,  240,  272,  304,  336,
 368,  400,  432,  464,  496,  528,  560,  592,  624,  656,
 688,  720,  752,  784,  816,  848,  880,  912,  944,  976,
1008, 1040, 1072, 1096, 1129, 1169, 1192, 1225, 1265, 1376  }

function print_tv(val)
    if ( val == nil ) then return("-") end
    local i = 1
    local tv_str = {
       ">64",
        "64",    "50",    "40",   "32",   "25",   "20",   "16",   "12",    "10",   "8.0",
       "6.0",   "5.0",   "4.0",  "3.2",  "2.5",  "2.0",  "1.6",  "1.3",   "1.0",   "0.8",
       "0.6",   "0.5",   "0.4",  "0.3",  "1/4",  "1/5",  "1/6",  "1/8",  "1/10",  "1/13",
      "1/15",  "1/20",  "1/25", "1/30", "1/40", "1/50", "1/60", "1/80", "1/100", "1/125",
     "1/160", "1/200", "1/250","1/320","1/400","1/500","1/640","1/800","1/1000","1/1250",
    "1/1600","1/2000","1/2500","1/3200","1/4000","1/5000","1/6400","1/8000","1/10000","hi"  }
    while (i <= #tv_ref) and (val > tv_ref[i]) do i=i+1 end
    return tv_str[i]
end
I think the original code here is something I got from msl (http://chdk.setepontos.com/index.php?action=profile;u=687).

I've also mused in the past about maybe having script access to the aperture_sizes_table[] in shooting.c so that scripts can generically "know" what f-stops are available on the camera (assuming the table is not just c&p'd from another camera and that it somehow still works at different zoom positions).
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: lapser on 28 / September / 2013, 15:05:02
So what you really need is a function to generate a human readable string from the Tv96 shutter speed value?

Since this would also be useful for ubasic it should probably be in the core C code.
YES!!!! Great idea, Phil. Now I'm excited again.

Here's how I would implement it:

sv96_to_string(sv96,precision)
av96_to_string(av96,precision)
tv96_to_string(tv96,precision)

precision is the number of digits after the decimal point. If 0, it would skip the decimal point.

By specifying the precision, the functions would round to the nearest digit. I.E.
av96_to_string(av96,1) would produce:   f 2.6 instead of f 2.612

The precision variable is important to me for sv96 too, for low ISO values. Each sv96 value should be able to produce a unique ISO result. It's not any more trouble to implement, and it might be useful in other ways we don't know about.

tv96_to_string(tv96,3) would produce "xx.xxx" for tv96<192 (>0.25 second), and "1/xx.xxx" for tv96>=192.

It might be useful to be able to force "xx.xxx" format. The easiest way to implement that would be to define precision<0 as "xx.xxx" only.

I'll see if I can get it working and post a patch and test script. The goal is to be able to use the functions directly in a "print" statement.

To make my script UI's "pretty",  I'm still not using the new APEX96 functions to create output strings.  Nothing wrong with the functions but what I want is shutter speeds in the same increments that Canon provides so that they match the exif values. So for example, any tv96 value between 560 & 592 is displayed as 1/60 sec.
Yes, I think we're on the same page here. That should work for 1/4 second or less with:
tv96_to_string(tv96,0)

But for >1/4, you'd want to use at least:
tv96_to_string(tv96,1)

This could be done easily in a script:

precision=0
if(tv96<192)then precision=1
print(tv96_to_string(tv96,precision))
=======
As for matching the EXIF values, that would require a table lookup, like the one in your script. It's probably better to keep doing that in the script, since it doesn't require floating point calculations. You might want to experiment with using the camera specific shutter and aperture tables in a separate function, kind of like set_tv96() and set_tv96_direct().
Title: Apex96 to string functions
Post by: lapser on 08 / October / 2013, 22:55:48
I've finished writing 3 new CHDK functions for Lua to convert and display tv96, av96, and sv96 to human readable strings. Please take a look at them and let me know if you want to add them to the trunk as is. If so, I'll add them for uBasic and post a patch. Here's a description of the functions, a test Lua script that uses them, and the log produced by the script (attached):

tv96_to_string(tv96 [,ndig] [,scale])
  ndig: 0..9  precision (digits after decimal point) 1/x format starts at 1/4 second
          10..19 no 1/x format  precision is last digit (%10)
          -1: (default) automatic ndig   Change of 1 tv96 unit always gives unique result (see log)
          -2: automatic ndig   No 1/x format
  scale: (default 1) Result multiplier. I.E. 1000 for msec

av96_to_string(av96 [,ndig] [,scale])
  ndig: 0..9  precision (digits after decimal point)
          -1: (default) automatic ndig   Change of 1 av96 unit always gives unique result
  scale: (default 1) Result multiplier

sv96_to_string(sv96 [,ndig] [,scale])
  ndig: 0..9  precision (digits after decimal point)   MARKET ISO result
          10..19 REAL ISO result    precision is last digit (%10)
          -1: (default) automatic ndig   MARKET ISO
          -2: automatic ndig   REAL ISO
  scale: (default 1) Result multiplier

Code: [Select]
--[[
@title ApexStr 1
@param d Dummy
@default d 1
--]]
print_screen(1)
print("Apex to String Test")
set_console_autoredraw(-1)
print()
av=aperture_to_av96(1000)
avlast=aperture_to_av96(40000)
print("av96 from",av,"to",avlast)
av=0
avlast=1000 -- aperture_to_av96 overflows
print("av96 | aperture_to_av96 | to_aperture | to_string 3 | to_string -1")
repeat
  f0=av96_to_aperture(av)
  print(string.format("%d | %d | %d | %s | %s",av,aperture_to_av96(f0),f0,av96_to_string(av,3),av96_to_string(av,-1)))
  av=av+1
until av>avlast

print()
sv=iso_to_sv96(25);
svlast=iso_to_sv96(6400);
print("sv96 from",sv,"to",svlast)
print("sv96 | to_iso | to_string 10 | to_string -2 | to_string -1")
repeat
  print(string.format("%d | %s | %s | %s | %s",sv,sv96_to_iso(sv),sv96_to_string(sv,10),sv96_to_string(sv,-2),sv96_to_string(sv)))
  sv=sv+1
until sv>svlast

print()
tv=seconds_to_tv96(256,1)
tvlast=seconds_to_tv96(1,8192)
print("tv96 from",tv,"to",tvlast)
print("tv96 | to_usec | to_string 10,1000000 | to_string -2,1000 | to_string -1")
repeat
  print(string.format("%d | %s | %s | %s | %s",tv,tv96_to_usec(tv),tv96_to_string(tv,10,1000000),tv96_to_string(tv,-2,1000),tv96_to_string(tv)))
  tv=tv+1
until tv>tvlast
set_console_autoredraw(1)

Title: Re: Apex96 to string functions
Post by: waterwingz on 08 / October / 2013, 23:13:42
I've finished writing 3 new CHDK functions for Lua to convert and display tv96, av96, and sv96 to human readable strings.
While technically correct,  these functions don't do anything useful for me.   

As per my previous post,  what I'm looking for is functions that convert APEX96 values to stings that look like the rounded values that Canon will use in their EXIF data.   These functions are for display only but would make it much easier to produce UI's that show Tv, Av, & Sv values users understand.

For example,  I would like Tv96 values between 560 &  592 to simply display as 1/60,  not 1/57.0 to 1/71.8.

Sorry - just MHO.
Title: Re: Apex96 to string functions
Post by: lapser on 08 / October / 2013, 23:52:28
As per my previous post,  what I'm looking for is functions that convert APEX96 values to stings that look like the rounded values that Canon will use in their EXIF data.   These functions are for display only but would make it much easier to produce UI's that show Tv, Av, & Sv values users understand.

For example,  I would like Tv96 values between 560 &  592 to simply display as 1/60,  not 1/57.0 to 1/71.8.
Don't you have a Lua script function that does that? It involves a table look up, and only integer math, so a CHDK function isn't really necessary.

We could put the table into CHDK and do the look up in C code instead of script, I suppose. Are we sure the table is camera independent? Each camera must have its own table in firmware somewhere, wouldn't it? Has anyone ever found that table in the firmware? Does the EXIF data end up showing values that the camera can't input using its own settings? How well does your script version match the EXIF data?

I think there are too many questions to be able to add that feature to my new functions at the moment. It could be easily added as a new option in the future, if we can figure out the correct table values.

But the question for now is, do you want to add these functions, as is, to the trunk? They're really useful to me to watch the exposure gradually change during a time lapse, in understandable units instead of apex96 numbers. The automatic precision works really well too. I couldn't do that properly in Lua. As Phil said, it would be useful to have this capability in uBasic too.
Title: Re: Apex96 to string functions
Post by: philmoz on 09 / October / 2013, 00:03:00
As per my previous post,  what I'm looking for is functions that convert APEX96 values to stings that look like the rounded values that Canon will use in their EXIF data.   These functions are for display only but would make it much easier to produce UI's that show Tv, Av, & Sv values users understand.

For example,  I would like Tv96 values between 560 &  592 to simply display as 1/60,  not 1/57.0 to 1/71.8.
Don't you have a Lua script function that does that? It involves a table look up, and only integer math, so a CHDK function isn't really necessary.

We could put the table into CHDK and do the look up in C code instead of script, I suppose. Are we sure the table is camera independent? Each camera must have its own table in firmware somewhere, wouldn't it? Has anyone ever found that table in the firmware? Does the EXIF data end up showing values that the camera can't input using its own settings? How well does your script version match the EXIF data?

I think there are too many questions to be able to add that feature to my new functions at the moment. It could be easily added as a new option in the future, if we can figure out the correct table values.

But the question for now is, do you want to add these functions, as is, to the trunk? They're really useful to me to watch the exposure gradually change during a time lapse, in understandable units instead of apex96 numbers. The automatic precision works really well too. I couldn't do that properly in Lua. As Phil said, it would be useful to have this capability in uBasic too.

Hard to review without the source code?

Phil.
Title: Re: Apex96 to string functions
Post by: waterwingz on 09 / October / 2013, 00:07:08
Don't you have a Lua script function that does that? It involves a table look up, and only integer math, so a CHDK function isn't really necessary.
True.  But the script has no idea of the valid shutter speed and aperture discrete values & range of the camera.

Quote
We could put the table into CHDK and do the look up in C code instead of script, I suppose. Are we sure the table is camera independent? Each camera must have its own table in firmware somewhere, wouldn't it?
I believe you will find that in the shooting.c file in the each camera's platform/camera directory.  Although its probably not safe to assume those are all correct and not just C&P from other posts,  it would be a good reason to clean them up on a camera by camera basis.

Quote
I think there are too many questions to be able to add that feature to my new functions at the moment. It could be easily added as a new option in the future, if we can figure out the correct table values.
I wasn't proposing adding it to your new functions.

Quote
But the question for now is, do you want to add these functions, as is, to the trunk? They're really useful to me to watch the exposure gradually change during a time lapse, in understandable units instead of apex96 numbers.
I think I may understand your fascination with three decimal accuracy for Tv, Av, & Sv values,  but I'm pretty sure most people don't really care that much.  And I'm almost certain you won't tell the difference in the images you shoot.
Title: Re: Apex96 to string functions
Post by: lapser on 09 / October / 2013, 01:24:22
I think I may understand your fascination with three decimal accuracy for Tv, Av, & Sv values,  but I'm pretty sure most people don't really care that much.  And I'm almost certain you won't tell the difference in the images you shoot.
What's important to me is that each tv96 value converts to a unique shutter time value, with the minimum # of digits. That's what the last column in the log file shows. I'm not talking about setting exposure or what the pictures look like. I'm talking about displaying the exposure accurately enough that you can tell when it changed. If the consensus is that this isn't important enough to have in the trunk, then I'll just leave it in my custom build.

Hard to review without the source code?
Before getting into how they're implemented, I'd like you to look at what the functions do, and  decide if you want this capability in the trunk. I've documented the function input and output options, and demonstrated that they work, with the test script and log file.

waterwingz seems to think that nobody but me would use the functions, and that they're not worth putting in the trunk. If that's the consensus, then there's no point in wasting all our time looking at source code.

Title: Re: Apex96 to string functions
Post by: Microfunguy on 09 / October / 2013, 05:12:57
waterwingz seems to think that nobody but me would use the functions, and that they're not worth putting in the trunk. If that's the consensus, then there's no point in wasting all our time looking at source code.

I am certainly interested in the practical results of your day-to-night timelapse but as I mentioned, if I implemented the feature I would just display the Tv96 number.

That tells me it is changing by the smallest possible increment.


David
Title: Re: Apex96 to string functions
Post by: philmoz on 09 / October / 2013, 06:32:29
I've finished writing 3 new CHDK functions for Lua to convert and display tv96, av96, and sv96 to human readable strings. Please take a look at them and let me know if you want to add them to the trunk as is. If so, I'll add them for uBasic and post a patch. Here's a description of the functions, a test Lua script that uses them, and the log produced by the script (attached):

tv96_to_string(tv96 [,ndig] [,scale])
  ndig: 0..9  precision (digits after decimal point) 1/x format starts at 1/4 second
          10..19 no 1/x format  precision is last digit (%10)
          -1: (default) automatic ndig   Change of 1 tv96 unit always gives unique result (see log)
          -2: automatic ndig   No 1/x format
  scale: (default 1) Result multiplier. I.E. 1000 for msec

av96_to_string(av96 [,ndig] [,scale])
  ndig: 0..9  precision (digits after decimal point)
          -1: (default) automatic ndig   Change of 1 av96 unit always gives unique result
  scale: (default 1) Result multiplier

sv96_to_string(sv96 [,ndig] [,scale])
  ndig: 0..9  precision (digits after decimal point)   MARKET ISO result
          10..19 REAL ISO result    precision is last digit (%10)
          -1: (default) automatic ndig   MARKET ISO
          -2: automatic ndig   REAL ISO
  scale: (default 1) Result multiplier

Code: [Select]
--[[
@title ApexStr 1
@param d Dummy
@default d 1
--]]
print_screen(1)
print("Apex to String Test")
set_console_autoredraw(-1)
print()
av=aperture_to_av96(1000)
avlast=aperture_to_av96(40000)
print("av96 from",av,"to",avlast)
av=0
avlast=1000 -- aperture_to_av96 overflows
print("av96 | aperture_to_av96 | to_aperture | to_string 3 | to_string -1")
repeat
  f0=av96_to_aperture(av)
  print(string.format("%d | %d | %d | %s | %s",av,aperture_to_av96(f0),f0,av96_to_string(av,3),av96_to_string(av,-1)))
  av=av+1
until av>avlast

print()
sv=iso_to_sv96(25);
svlast=iso_to_sv96(6400);
print("sv96 from",sv,"to",svlast)
print("sv96 | to_iso | to_string 10 | to_string -2 | to_string -1")
repeat
  print(string.format("%d | %s | %s | %s | %s",sv,sv96_to_iso(sv),sv96_to_string(sv,10),sv96_to_string(sv,-2),sv96_to_string(sv)))
  sv=sv+1
until sv>svlast

print()
tv=seconds_to_tv96(256,1)
tvlast=seconds_to_tv96(1,8192)
print("tv96 from",tv,"to",tvlast)
print("tv96 | to_usec | to_string 10,1000000 | to_string -2,1000 | to_string -1")
repeat
  print(string.format("%d | %s | %s | %s | %s",tv,tv96_to_usec(tv),tv96_to_string(tv,10,1000000),tv96_to_string(tv,-2,1000),tv96_to_string(tv)))
  tv=tv+1
until tv>tvlast
set_console_autoredraw(1)

I think the basic concept is worthwhile; but:
- there are far too many 'magic' numbers in the implementation.
- I don't understand the need for the scale parameters.

If I were implementing something like this I would pass the C style format string to the function instead of 'ndig', i.e.:
- "%f" = generic floating point format
- "%.2f" =  2 decimal places
- "%6.2f" = total width of 6 with 2 decimal places, right justified
- "%-6.2f" = total width of 6 with 2 decimal places, left justified

If you want to make the 1/X format optional in the Tv function, add another boolean parameter to control it - overloading parameters (ndig) with special meanings is a poor design practice.

Phil.
Title: Re: Apex96 to string functions
Post by: lapser on 09 / October / 2013, 13:59:46
I think the basic concept is worthwhile; but:
- there are far too many 'magic' numbers in the implementation.
- I don't understand the need for the scale parameters.

If you want to make the 1/X format optional in the Tv function, add another boolean parameter to control it - overloading parameters (ndig) with special meanings is a poor design practice.
Thanks for the suggestions. I agree that it's good to avoid "magic numbers", but not at the expense of losing capability, like accuracy. One capability that you didn't mention is the variable precision of the output, based on the difference between the results for tv96 and tv96+1 (or sv, av). This "auto-ndig" capability is the main reason I wrote these functions.

The scale factor is important for choosing the units for the output, i.e. msec instead of usec. I would much rather output "1 usec" or "0.001 msec" than "0.000001" sec.  And "128 sec" is a lot easier to read than "128000000 usec".

tv96_to_usec(tv96) is fine, if all you want to output is usec within a limited range. But then we need a more flexible string output function, including a scale option.
Quote
If I were implementing something like this I would pass the C style format string to the function instead of 'ndig', i.e.:
- "%f" = generic floating point format
- "%.2f" =  2 decimal places
- "%6.2f" = total width of 6 with 2 decimal places, right justified
- "%-6.2f" = total width of 6 with 2 decimal places, left justified
I don't think implementing generic floating point is worth the effort. The width and justification can be done in the script with string.format(%s).

For tv96, 1/x format starts automatically at 1/4 seconds, like the camera displays. If we're adding another parameter, it would be nice to be able to change the crossover value.

So how about this definition?

tv96_to_string(tv96 [, ndig, inverse, scale])
optional paramters with default (optnumber)
ndig: 0..9: precision
      <0 or >9: automatic (default)
inverse: true: 1/x starting at 1/4 second (192 tv96)  (default)
         false: no 1/x
         number: tv96 value where 1/x starts. i.e. 96 to start at 1/2 second
scale:  multiplier (default 1)

For ubasic, I'd be happy with just 1 parameter, tv96, and the rest would use the default values. Lua would only require one parameter, so it would work the same way, but with more options.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: philmoz on 10 / October / 2013, 07:13:59
An alternative approach to think about.

It seems to me the goal here is to convert an APEX96 value to a human readable string.

Why not use a single 'apex_to_string' function defined as:
    char* apex_to_string(int apex96, char* format)

Where:
- apex96 is the value to convert
- format is a control string to determine how the output is generated.

The format parameter takes the form:
    "[[-]w][.d]x"
where:
- w = pad output to 'w' width right justified unless the '-' is included, default is no padding
- .d = # of decimal digits to output, if not included then defaults to 0
- x = format control, one of the following
    - s = ISO conversion
    - S = ISO conversion, mapped to nearest Canon value
    - a = Aperture conversion
    - A = Aperture conversion, mapped to nearest Canon value
    - t or u = Shutter speed conversion
    - T or U = Shutter speed conversion, mapped to nearest Canon value

For shutter speed the following conversion rules would apply:
- t or T
    - > 1/4 second - output in seconds
    - <= 1/4 second - output as 1/X seconds
- u or U
    - >= 1 second - output in seconds
    - < 1 second, >= 1 millisecond, output in milliseconds
    - < 1 millisecond - output in microseconds

The 'u' or 'U' conversion would also need to append the units to the output (secs, msec or usec).

The 'S', 'A', 'T', and 'U' variations find the nearest Canon allowed value as defined in shooting.c. For values less than the minimum it could add a leading '<', and for greater than the max, add a '>'.

Phil.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: Microfunguy on 10 / October / 2013, 07:44:59

It seems to me the goal here is to convert an APEX96 value to a human readable string.

I still do not get it, what is unreadable about APEX96 values ?

They are just a number, the user simply needs to detect they are changing by a unit increment (as far as the shot histogram application is concerned).
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: waterwingz on 10 / October / 2013, 09:25:13
An alternative approach to think about.

....

The 'S', 'A', 'T', and 'U' variations find the nearest Canon allowed value as defined in shooting.c. For values less than the minimum it could add a leading '<', and for greater than the max, add a '>'.
Two thumbs up from me on this one.  Exactly what I was looking for.

I still do not get it, what is unreadable about APEX96 values ?
I'd like to remind you that you frequently enjoy pointing out the difference between programmers and photographers.   Until one of the camera manufacturers starts selling cameras that display APEX96 values,  its would seem most photographers expect to see fractional seconds, f-stops and ISO sensitivity values in the UI.

Quote
They are just a number, the user simply needs to detect they are changing by a unit increment (as far as the shot histogram application is concerned).
Shot histograms is just one use case.
Title: Re: 1.3 development proposal - exposure conversion functions
Post by: Microfunguy on 10 / October / 2013, 14:14:45
I'd like to remind you

As a matter of interest, does your present employment (if not retired) or previous employment involve the supervision of small groups of people ?

Title: Re: 1.3 development proposal - exposure conversion functions
Post by: lapser on 10 / October / 2013, 20:40:08
An alternative approach to think about.
Those are some very good ideas, but it wouldn't do what my current functions do, in that it doesn't provide for a scale factor and automatic number of digits of precision based on (apex96+1). It would also take more work and code to implement. It seems like there are a lot of "magic letters" to learn too.

I'm leaning towards unifying all the conversion functions into two functions:

apex96_from(type, val, mult)
  type: "shutter", "iso", "aperture"
  val: value for shutter, iso, or aperture
  mult: multiplier (negative means use 1/val)
      (double) dval = val*mult or 1/(-mult*val)
      default if mult isn't present: 1
  returns: integer apex96 value
example: 1/3200 shutter  tv96=apex96_from("shutter",3200,-1)

apex96_to( type, apex96, mult, ndig)
  type: same as above, plus "*shutter","*iso", "*aperture" for string output
  apex96: tv96, sv96, or av96 based on type
  mult:: multiplier for result, negative means 1/x
            default if mult isn't present is 1
  ndig: for string types only
           #digits of precision 0 to 9, or -1 for auto.
          Default, if ndig isn't present is -1 auto
  returns: integer or string

For waterwingz request of returning only camera valid values, you could start the type with "=" instead of "*"

apex96_to("=shutter",apex96)
  would return a string with the nearest valid camera value. ndig and scale determined by valid value format
========
Before jumping on me for suggesting new things that have already been decided, what I'm considering doing is a separate patch for my own builds that I'll provide independently to those that want to use it, instead of trying to get it in the trunk. This will eliminate all the arguing, and free me up to think more creatively.