Thursday, October 31, 2024

Handling long operations in observer chains

If you have lengthy observer notification chains where observers notify other observers, making the trigger order unpredictable, and these chains include time-consuming operations like updating a map drawing, you can use the following approach to only update the drawing when the last observer in the chain is reached:

Thursday, October 24, 2024

chatGPT 4o vs o1-preview

I normally use chatGPT 4o because it is much faster than o1-preview. Today I asked 4o the following:

Write a function that performs the following 2 byte hex to 2 byte signed int transformations:
0x801D --> -29
0x811D --> -285
0x821D --> -541
0xFF1D --> -32541
0x001D --> 29
0xAA1D --> -10781
0x101D --> 4125

It wrote a function that resulted in the following, mostly wrong, output:

-32739
-32483
-32227
-227
29
-21987
4125

I fed this output back, and it apologized and rewrote something slightly different, but the output was still wrong. I repeated the steps, and I got responses like 'I see the issue more clearly now' and 'Thank you for your patience,' but the output remained incorrect. When I fed the same prompt to o1-preview, it solved the problem in a single iteration. Here is the final python function (sign-magnitude representation):

def hex_to_signed_int(N):
    isNegative = N & 0x8000 # equivalent to "N >= 0x8000"
                            # 0x8000=1000 0000 0000 0000
    if isNegative:
        magnitude = N & 0x7FFF # 0x7FFF=0111 1111 1111 1111
        return -magnitude
    else:
        return N

test_values = [0x801D, 0x811D, 0x821D, 0xFF1D, 0x001D, 0xAA1D, 0x101D]

for val in test_values:
    print(f"0x{val:04X} --> {val:05} --> {hex_to_signed_int(val)}")

Sunday, September 22, 2024

Using code from Simulink model in HIL

Steps of converting a Simulink model to code usable in Hardware-in-the-loop (HIL) simulation:
  1. Checkout/pull Simulink model from repository to your local.
  2. Run Simulink model and confirm it finishes as expected. If not, inform the model maintainer and ask them to commit/push the model with correct settings to repo. 
  3. Confirm that C/C++ code can be generated from model. Sometimes an s-function build file (mexw64) exists but its source code is missing, which allows the model to run but prevents code generation.
  4. Copy code to Visual Studio and verify that you can build and run it. There are cases where Simulink is more forgiving of errors like uninitialized variables, or missing #include <cmath> but Visual Studio cannot build the code.
  5. Copy code to real time Linux PC and verify code can be build there too.
  6. Commit code to its own repo.
  7. Run HIL with new code and verify HIL works as expected.

Monday, September 9, 2024

Why is file hash comparison faster than byte-wise comparison

Question: Since calculating the hash of a file requires reading every byte, why is comparing hashes of two files faster than byte wise comparison of file contents?

Answer: In hash comparison, each file's hash is computed once (by reading all its bytes), and then the two hashes, which are small fixed-size values (e.g., 256-bit or 512-bit), are compared. Comparing two hashes takes constant time, regardless of file size. In a byte-wise comparison, if there are N bytes, in the worst case where files are the same, N comparisons have to be made. 
  • Hash comparison = reading file + 1 comparison.
  • Byte-wise comparison = reading file + N comparisons.

Tuesday, July 30, 2024

LONG_MAX is different for Windows 64 and Linux 64

When you generate code with Simulink (MATLAB R2023b) using ert.tlc, the default OS is Windows 64, see Configuration Parameters - Hardware Implementation - Device type. When you generate C code, the <model name>_private.h file will contain checks for ULONG_MAX and LONG_MAX.

On 64-bit Windows, the long type is typically 32 bits, which causes the LONG_MAX to be 0x7FFFFFFF. On 64-bit Linux systems, the long type is typically 64 bits, i.e. LONG_MAX is 0x7FFFFFFFFFFFFFFF. When you use code generated with the Windows 64 setting and use that on a Linux 64 OS, the check in <model name>_private.h will fail. The solution is to use the Linux 64 setting in Simulink which removes the LONG_MAX check from header file.

This checks seem to have been added after MATLAB R2022b because code generated with R2022b does not have them.

Friday, July 12, 2024

Passing JSON to ProcessBuilder

I am using one JVM to prepare inputs for a simulation in another JVM. The simulation uses a C++ DLL, and when that DLL crashes, it takes the JVM with it. Running it in a separate JVM protects the first JVM from crashing as well. I prepare the simulation inputs as a JSON string in the first JVM and pass it to the second using ProcessBuilder. However, when passing a standard JSON, ProcessBuilder strips away the double quotes, e.g., "count": 5 becomes count: 5, which results in an invalid JSON that cannot be parsed in the main(String[] args) method. The workaround is to use jsonStr.replace("\"", "\\\"") before passing jsonStr to ProcessBuilder.

Tuesday, March 26, 2024

When do you need HIL tests?

The steps to create an autonomous aircraft, from design to product, are as follows:
  1. Concept of Operation
  2. Requirements
  3. Design
  4. Ground tests
    1. Test components
    2. Test system
  5. Flight tests
  6. Deployment
  7. Maintenance/Updates
As you progress through these steps, the cost of fixing problems increases exponentially.

Consider a typical closed-loop diagram:
The "plant" consists of the airframe, actuators, and engine. The environment includes the atmosphere, aerodynamics, gravity, and electromagnetic interference.

During design phase, you start without any hardware and simulate everything with software-in-the-loop (SIL) simulations. The advantage of SIL is that it allows you to run millions of automated tests in a short time and with low cost to verify that you don't have any logic errors in your software. 

As hardware becomes available, you proceed to ground tests, transitioning more and more of your software from standard PCs to custom hardware. This slower and more costly step is called hardware-in-the-loop (HIL/HWIL) tests. HIL tests are necessary because:
  1. Your system might work in SIL but since certain bugs only manifest themselves on a particular OS - compiler - hardware configuration, you cannot be sure with just SIL tests that your software is bug-free. Note: Instead of bug-free, the term 'tolerable' might be more appropriate because, for complex software, it is statistically improbable to achieve an entirely bug-free state.
  2. Resource constraints (memory, processing power, network speed, etc.) of real hardware might differ from those in SIL which might cause a working system in SIL to fail in HIL due to missed timings etc.
  3. Electromagnetic conditions (interference, noise, etc.) might differ from those in SIL. Components that work individually in isolation might cause problems when integrated together.
  4. Although you can't test as extensively as with SIL, you can still conduct far more tests than with flight tests.