Page 1 of 1
Sharing Math Channels for E46 M3
Author Message
Sharing Math Channels for E46 M3
I've recently discovered how to add math channels to the E46 standard script that I have been using and wanted to share them here. The calculations have mostly come from the book "analysis techniques for racecar data acquisition" by Jorge Segers. I've condensed some of the calculations and scaling factors to reduce the length of the equations and so it may not be completely clear from the script.I have not tested these out on a track yet, just driving around the block. I make no claims to their accuracy or usefulness.

I will copy the whole script in the next post but wanted to explain each of the math channels individually. The channel Id should be added to you list of channels at the top of the script.
The calculation should be added after the "processCAN(CAN_chan)" line which can be found immediatly after the can map section.
i.e.
function onTick()
processCAN(CAN_chan)
end

Gear Calculator. This is for the E46 M3 with standard diff ratio (3.62)

local a1=getChannel(rpmId)
local a2=getChannel(clutchId)
local a3=getChannel(gearId)
local w3=getChannel(lrWheelId)
if a2<0.5 then
setChannel(gearId,(w3/a1)*240)
else
setChannel(gearId,a3)
end

This channel works by dividing the wheel speed by the rpm and multiplying that value by 240. Using no decimal places it matches the gear position. The gear calculator runs when the clutch is engaged. When the clutch is disengaged, the gear calculator remembers the last position. This will prevent erroneous numbers when blipping the throttle on a down shift.

Wheel Longitudinal slip.

This channel will calculate the forward/aft slip of the individual wheels. This will measure wheelspin during acceleration and wheel lockup under braking.

Channels:

Calculation:
local w1=getChannel(lfWheelId)
local w2=getChannel(rfWheelId)
local w3=getChannel(lrWheelId) -- not needed here is using with gear calculator above.
local w4=getChannel(rrWheelId)
if w4 > 10 then
setChannel(lfslipId,100-(50*(w3+w4))/w1)
setChannel(rfslipId,100-(50*(w3+w4))/w2)
setChannel(lrslipId,100-(50*(w1+w2))/w3)
setChannel(rrslipId,100-(50*(w1+w2))/w4)
end

This one works by tacking the average speed of the wheels on one axel and comparing that to the speed of a wheel on the other axel. The calculation is only performed at greater than 10 mph otherwise it provide lager slip angles when speeds are low. I also increased the wheel speed channel to 1 decimal place to get better accuracy with these calculations.

The brakeG channel is to separate out the areodynamic drag force from the decceleration G-Froce to leave just the braking effort. This channel was created as there is no brake pressure channel on the CANBUS. The math is from this website http://www.jameshakewill.com/brake-trace.pdf

The totalG channel is to assess the transition from braking to turing to ensure.

local g1=getImu(0)
local u3=getGpsSpeed()
local b2=(-1*g1)-((u3^2/10000)
if b2>0 then
setChannel(brakegId,b2)
end
local g2=getImu(1)
local g3=((g1^2)+(g2^2))^(0.5)
setChannel(totalgId,g3)

And finally Calculated Power. This uses a lot of numbers about the car that may be slightly different on mine than others. For example, this calculation uses the weight (3500lbs including me), tyre size (255/40/17 for me) as well as Cd, frontal, area, gear ratios and a few other things that i have probably forgotten. There were a lot of individual calculations that I tried to reduce to the bare minimum to keep the code as small as possible.

Channel:

Calculation:
local p1=468.2+(0.080845*(u3)^2)
local p2=(16232+0.22125*(a1/u3)^2)*g1
if g1>0 then
setChannel(powerId,(p1+p2)*(u3/1677.85))
end

tickRate=30

CAN_baud=500000

CAN_chan=0

function rpmFilter(value)

if value > 500 then startLogging() else stopLogging() end

return value

end

function brakeFilter(value)

return bit.rshift(bit.band(value,0x10),4)

end

function clutchFilter(value)

return bit.band(value,0x01)

end

function processWheel(id,data,offset)

local highByte = bit.band(data[offset+2], 0x1F)

local lowByte = data[offset+1]

local value = highByte*256+lowByte

value = (value*0.0388357)-0.3

setChannel(id, value)

end

function processSteering(data)

local steer=0

if data[2]>127 then

steer=-1*(((data[2]-128)*256)+data[1])

else

steer=(data[2]*256)+data[1]

end

setChannel(steerId,(steer*0.045))

end

function fuelFilter(value)

value = bit.band(value,0x7F)

return value/0.6283

end

function extTempFilter(value)

local temp = bit.band(value,0x7F)

if value>127 then

temp =-1*temp

end

end

CAN_map = {

[496] = function(data) processWheel(lfWheelId,data,0) processWheel(rfWheelId,data,2) processWheel(lrWheelId,data,4) processWheel(rrWheelId,data,6) end,

[339] = function(data) map_chan(brakeId,data,0,1,1,0,brakeFilter) end,

[809] = function(data) map_chan(tpsId,data,5,1,0.392156863,0) map_chan(coolantId,data,1,1,0.75,-4 map_chan(clutchId,data,3,1,1,0,clutchFilter) map_chan(cruiseId,data,3,1,1,0) end,

[1349] = function(data) map_chan(oilTempId,data,4,1,1,-4 end,

[790] = function(data) map_chan(rpmId,data,2,2,0.15625,0,rpmFilter) end,

[501] = function (data) processSteering(data) end,

[1555] = function (data) map_chan(fuelId,data,2,1,1,0,fuelFilter) end,

[1557] = function (data) map_chan(extTempId,data,3,1,1,0,extTempFilter) end

}

function onTick()

processCAN(CAN_chan)

local a1=getChannel(rpmId)

local a2=getChannel(clutchId)

local a3=getChannel(gearId)

local w3=getChannel(lrWheelId)

if a2<0.5 then

setChannel(gearId,(w3/a1)*240)
else

setChannel(gearId,a3)

end

local w1=getChannel(lfWheelId)

local w2=getChannel(rfWheelId)

local w4=getChannel(rrWheelId)

if w4 > 10 then

setChannel(lfslipId,100-(50*(w3+w4))/w1)

setChannel(rfslipId,100-(50*(w3+w4))/w2)

setChannel(lrslipId,100-(50*(w1+w2))/w3)

setChannel(rrslipId,100-(50*(w1+w2))/w4)

end

local g1=getImu(0)

local u3=getGpsSpeed()

local b2=(-1*g1)-((u3^2/10000)

if b2>0 then

setChannel(brakegId,b2)

end

local g2=getImu(1)

local g3=((g1^2)+(g2^2))^(0.5)

setChannel(totalgId,g3)

local p1=468.2+(0.080845*(u3)^2)

local p2=(16232+0.22125*(a1/u3)^2)*g1

if g1>0 then

setChannel(powerId,(p1+p2)*(u3/1677.85))

end

end

function processCAN(chan)

local msg = 0

repeat

local id, e, data = rxCAN(chan, 0)

if id ~= nil then

local map = CAN_map[id]

if map ~= nil then

map(data)
end

end

msg = msg+1

until id == nil or msg>100

end

function map_chan(cid, data, offset, len, mult, add, filter)

if offset + len > #data then return end

offset = offset + 1

local value=0

local shift=1

while len>0 do

value=value+(data[offset]*shift)

shift=shift*256

offset=offset+1

len=len-1

end

local cv = value * mult + add

if filter ~= nil then cv = filter(cv) end

setChannel(cid, cv)
end

initCAN(CAN_chan, CAN_baud)

setTickRate(tickRate)

This is quite fantastic, thank you for sharing. How is the data working for you so far?

We are soon introducing the next-gen CAN mapping capabilities, which will offload the raw CAN mapping out of Lua, and allow Lua to do what it's best at - creating calculated / math channels, just like you've done here.

Thanks again,

_________________
Brent Picasso
Founder, Autosport Labs

That's good to know. Will that mean that there will be more memory available or will it still be the combination of can channels and math channels?

You'll have more memory because you won't need write all of the code to do the CAN mapping in Lua. It's a performance improvement and memory saving combo win-win.

_________________
Brent Picasso
Founder, Autosport Labs

Mustangkev, is your BrakeG code working? As written i don't think the value will update when the value swings negative and is set to zero. Mine looks like this:

###### Code:
function updateBrakeG()
local accel_x = getImu(0)
local brake = -accel_x - speed^2/50000      --maybe 10000
if brake < 0 then
brake = 0
end
setChannel(brakeg_id, brake)
end

This way setChannel is called no matter what.

The brakeG would go to zero if the value went negative.
Although I haven't been using it recently, I've tried to implement the new can mapping and can't get it to read the can channels in Lua yet.

 Display posts from previous: All Posts1 Day7 Days2 Weeks1 Month3 Months6 Months1 Year Oldest FirstNewest First
 Page 1 of 1
 You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot vote in polls in this forumYou cannot attach files in this forumYou cannot download files in this forum Select a forum Autosport Labs----------------General DiscussionNews and AnnouncementsNew Project Suggestions CAN Devices----------------ShiftX2AnalogX RaceCapture App----------------RaceCapture App Operation and General Q&ARaceCapture App Bug Reporting / Feature Requests CAN bus and OBDII integration----------------CAN mapping discussionOBDII PIDs discussion RaceCapture/Pro | RaceCapture/Apex | PodiumConnect----------------RaceCapture/Pro introductionsRaceCapture/Pro General Q&ASensorsHardware and InstallationLua ScriptingTelemetryBug ReportingFeature Requests RaceCapture/Track----------------RaceCapture/Track IntroductionsRaceCapture/Track OperationRaceCapture/Track InstallationRaceCapture/Track Bug Reporting / Feature Requests Megajolt/E and Megajolt Lite Jr. (MJLJ)----------------Ignition Map LibraryPowered by Megajolt GalleryAssemblyInstallationOperationQ&AFuture UpgradesBug ReportingFixes/Patches/UpdatesHard Rev Limiter